<!DOCTYPE html>
<html lang="zh-CN">





<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/myblog/img/apple-touch-icon.png">
  <link rel="icon" type="image/png" href="/myblog/img/favicon.png">
  <meta name="viewport"
        content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="description" content="TakCode Blog">
  <meta name="author" content="谢芃">
  <meta name="keywords" content="">
  <title>Vue学习笔记 - TakCode</title>

  <link  rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/5.12.1/css/all.min.css" />
<link  rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.4.1/css/bootstrap.min.css" />
<link  rel="stylesheet" href="https://cdn.staticfile.org/mdbootstrap/4.13.0/css/mdb.min.css" />
<link  rel="stylesheet" href="https://cdn.staticfile.org/github-markdown-css/3.0.1/github-markdown.min.css" />

<link rel="stylesheet" href="//at.alicdn.com/t/font_1067060_qzomjdt8bmp.css">



  <link  rel="stylesheet" href="/myblog/lib/prettify/tomorrow-night-eighties.min.css" />

<link  rel="stylesheet" href="/myblog/css/main.css" />


  <link defer rel="stylesheet" href="https://cdn.staticfile.org/fancybox/3.5.7/jquery.fancybox.min.css" />


<!-- 自定义样式保持在最底部 -->


<meta name="generator" content="Hexo 4.2.0"></head>


<body>
  <header style="height: 70vh;">
    <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand"
       href="/myblog/">&nbsp;<strong>TakCode</strong>&nbsp;</a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
          <li class="nav-item">
            <a class="nav-link" href="/myblog/">首页</a>
          </li>
        
          
          
          
          
          <li class="nav-item">
            <a class="nav-link" href="/myblog/archives/">归档</a>
          </li>
        
          
          
          
          
          <li class="nav-item">
            <a class="nav-link" href="/myblog/categories/">分类</a>
          </li>
        
          
          
          
          
          <li class="nav-item">
            <a class="nav-link" href="/myblog/tags/">标签</a>
          </li>
        
          
          
          
          
          <li class="nav-item">
            <a class="nav-link" href="/myblog/about/">关于</a>
          </li>
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" data-toggle="modal" data-target="#modalSearch">&nbsp;&nbsp;<i
                class="iconfont icon-search"></i>&nbsp;&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

    <div class="view intro-2" id="background" parallax=true
         style="background: url('/myblog/img/default.png') no-repeat center center;
           background-size: cover;">
      <div class="full-bg-img">
        <div class="mask rgba-black-light flex-center">
          <div class="container text-center white-text fadeInUp">
            <span class="h2" id="subtitle">
              
            </span>

            
              
                <p class="mt-3 post-meta">
                  <i class="fas fa-calendar-alt" aria-hidden="true"></i>
                  星期日, 五月 5日 2019, 11:12 晚上
                </p>
              

              <p class="mt-1">
                
                  
                  <span class="post-meta">
                    <i class="far fa-chart-bar"></i>
                    29.9k 字
                  </span>
                

                
                  
                  <span class="post-meta">
                      <i class="far fa-clock"></i>
                      138 分钟
                  </span>
                

                
              </p>
            
          </div>

          
        </div>
      </div>
    </div>
  </header>

  <main>
    
      

<div class="container-fluid">
  <div class="row">
    <div class="d-none d-lg-block col-lg-2"></div>
    <div class="col-lg-8 nopadding-md">
      <div class="container nopadding-md" id="board-ctn">
        <div class="py-5 z-depth-3" id="board">
          <div class="post-content mx-auto" id="post">
            
            <div class="markdown-body">
              <p>Vue学习笔记</p>
<a id="more"></a>
<h3 id="Vue-是什么？"><a href="#Vue-是什么？" class="headerlink" title="Vue 是什么？"></a>Vue 是什么？</h3><ul>
<li><strong>Vue (读音 /vjuː/，类似于 **view</strong>) 是一套用于构建用户界面的渐进式框架**</li>
<li>vue 的核心库只关注视图层，不仅易于上手，还便于与第三方库或既有项目整合</li>
</ul>
<h3 id="使用Vue将helloworld-渲染到页面上-（Vue语法–-gt-原生语法）"><a href="#使用Vue将helloworld-渲染到页面上-（Vue语法–-gt-原生语法）" class="headerlink" title="使用Vue将helloworld  渲染到页面上 （Vue语法–&gt; 原生语法）"></a>使用Vue将helloworld  渲染到页面上 （Vue语法–&gt; 原生语法）</h3><img  src="http://helloxx.cn/day01-1.png" srcset="/myblog/img/loading.gif"  >

<h3 id="指令"><a href="#指令" class="headerlink" title="指令"></a>指令</h3><ul>
<li>指令本质就是自定义属性</li>
<li>Vue中指令都是以 v- 开头 </li>
</ul>
<h3 id="v-cloak"><a href="#v-cloak" class="headerlink" title="v-cloak"></a>v-cloak</h3><ul>
<li><p>防止页面加载时出现闪烁问题</p>
<pre><code class="html"> &lt;style type=&quot;text/css&quot;&gt;
  [v-cloak]{
    /* 元素隐藏    */
    display: none;
  }
  &lt;/style&gt;
&lt;body&gt;
  &lt;div id=&quot;app&quot;&gt;
    &lt;!-- 2、 让带有插值 语法的   添加 v-cloak 属性 
         在 数据渲染完场之后，v-cloak 属性会被自动去除，
         v-cloak一旦移除也就是没有这个属性了  属性选择器就选择不到该标签
         也就是对应的标签会变为可见
    --&gt;
    &lt;div  v-cloak  &gt;{{msg}}&lt;/div&gt;
  &lt;/div&gt;
  &lt;script type=&quot;text/javascript&quot; src=&quot;js/vue.js&quot;&gt;&lt;/script&gt;
  &lt;script type=&quot;text/javascript&quot;&gt;
    var vm = new Vue({
      el: &#39;#app&#39;,
      data: {
        msg: &#39;Hello Vue&#39;
      }
    });
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
</li>
</ul>
<h2 id="数据绑定指令"><a href="#数据绑定指令" class="headerlink" title="数据绑定指令"></a>数据绑定指令</h2><p>v-text 填充纯文本-  相比插值表达式更加简洁 </p>
<p>v-html 填充HTML片段- 存在安全问题，本网站内部数据可以使用，来自第三方的数据不可以用 </p>
<p>v-pre 填充原始信息- 显示原始信息，跳过编译过程（分析编译过程） </p>
<h3 id="v-text"><a href="#v-text" class="headerlink" title="v-text"></a>v-text</h3><ul>
<li>v-text指令用于将数据填充到标签中，作用于插值表达式类似，但是没有闪动问题</li>
<li>如果数据中有HTML标签会将html标签一并输出</li>
<li>注意：此处为单向绑定，数据对象上的值改变，插值会发生变化；但是当插值发生变化并不会影响数据对象的值</li>
</ul>
<pre><code class="html">&lt;div id=&quot;app&quot;&gt;
    &lt;!--注意:在指令中不要写插值语法  直接写对应的变量名称 
        在 v-text 中 赋值的时候不要再写插值语法--&gt;
    &lt;p v-text=&quot;msg&quot;&gt;&lt;/p&gt;
    &lt;p&gt;
        &lt;!-- Vue 中只有在标签的 内容中 才用插值语法 --&gt;
        {{msg}}
    &lt;/p&gt;
&lt;/div&gt;
&lt;script&gt;
    new Vue({
        el: &#39;#app&#39;,
        data: {
            msg: &#39;Hello Vue.js&#39;
        }
    });
&lt;/script&gt;</code></pre>
<h3 id="v-html"><a href="#v-html" class="headerlink" title="v-html"></a>v-html</h3><ul>
<li><p>用法和v-text 相似  但是他可以将HTML片段填充到标签中</p>
</li>
<li><p>可能有安全问题, 一般只在可信任内容上使用 <code>v-html</code>，<strong>永不</strong>用在用户提交的内容上</p>
</li>
<li><p>它与v-text区别在于v-text输出的是纯文本，浏览器不会对其再进行html解析，但v-html会将其当html标签解析后输出。</p>
<pre><code class="html">&lt;div id=&quot;app&quot;&gt;
　　&lt;p v-html=&quot;html&quot;&gt;&lt;/p&gt; &lt;!-- 输出：html标签在渲染的时候被解析 --&gt;

    &lt;p&gt;{{message}}&lt;/p&gt; &lt;!-- 输出：&lt;span&gt;通过双括号绑定&lt;/span&gt; --&gt;

　　&lt;p v-text=&quot;text&quot;&gt;&lt;/p&gt; &lt;!-- 输出：&lt;span&gt;html标签在渲染的时候被源码输出&lt;/span&gt; --&gt;
&lt;/div&gt;
&lt;script&gt;
　　let app = new Vue({
　　el: &quot;#app&quot;,
　　data: {
　　　　message: &quot;&lt;span&gt;通过双括号绑定&lt;/span&gt;&quot;,
　　　　html: &quot;&lt;span&gt;html标签在渲染的时候被解析&lt;/span&gt;&quot;,
　　　　text: &quot;&lt;span&gt;html标签在渲染的时候被源码输出&lt;/span&gt;&quot;,
　　}
 });
&lt;/script&gt;</code></pre>
</li>
</ul>
<h3 id="v-pre"><a href="#v-pre" class="headerlink" title="v-pre"></a>v-pre</h3><ul>
<li>显示原始信息跳过编译过程</li>
<li>跳过这个元素和它的子元素的编译过程。</li>
<li><strong>一些静态的内容不需要编译加这个指令可以加快渲染</strong></li>
</ul>
<pre><code class="html">&lt;span v-pre&gt;{{ this will not be compiled }}&lt;/span&gt;    
&lt;!--  显示的是{{ this will not be compiled }}  --&gt;
&lt;span v-pre&gt;{{msg}}&lt;/span&gt;  
&lt;!--   即使data里面定义了msg这里仍然是显示的{{msg}}  --&gt;
&lt;script&gt;
    new Vue({
        el: &#39;#app&#39;,
        data: {
            msg: &#39;Hello Vue.js&#39;
        }
    });
&lt;/script&gt;</code></pre>
<h2 id="数据响应式"><a href="#数据响应式" class="headerlink" title="数据响应式"></a>数据响应式</h2><p> 如何理解响应式  </p>
<ul>
<li>html5中的响应式（屏幕尺寸的变化导致样式的变化）</li>
<li>数据的响应式（数据的变化导致页面内容的变化） </li>
</ul>
<p>数据绑定：将数据填充到标签中 </p>
<h3 id="v-once"><a href="#v-once" class="headerlink" title="v-once"></a><strong>v-once</strong></h3><ul>
<li>执行一次性的插值【当数据改变时，插值处的内容不会继续更新】</li>
</ul>
<pre><code class="html">&lt;!-- 即使data里面定义了msg 后期我们修改了 仍然显示的是第一次data里面存储的数据即 Hello Vue.js  --&gt;
&lt;span v-once&gt;{{ msg}}&lt;/span&gt;    
&lt;script&gt;
    new Vue({
        el: &#39;#app&#39;,
        data: {
            msg: &#39;Hello Vue.js&#39;
        }
    });
&lt;/script&gt;</code></pre>
<h3 id="双向数据绑定"><a href="#双向数据绑定" class="headerlink" title="双向数据绑定"></a>双向数据绑定</h3><ul>
<li>当数据发生变化的时候，视图也就发生变化</li>
<li>当视图发生变化的时候，数据也会跟着同步变化</li>
</ul>
<h4 id="v-model"><a href="#v-model" class="headerlink" title="v-model"></a>v-model</h4><ul>
<li><strong>v-model</strong>是一个指令，限制在 <code>&lt;input&gt;、&lt;select&gt;、&lt;textarea&gt;、components</code>中使用</li>
</ul>
<pre><code class="html"> &lt;div id=&quot;app&quot;&gt;
      &lt;div&gt;{{msg}}&lt;/div&gt;
      &lt;div&gt;
          当输入框中内容改变的时候，页面上的msg 会自动更新
        &lt;input type=&quot;text&quot; v-model=&#39;msg&#39;&gt;
      &lt;/div&gt;
  &lt;/div&gt;</code></pre>
<h3 id="mvvm设计思想"><a href="#mvvm设计思想" class="headerlink" title="mvvm设计思想"></a>mvvm设计思想</h3><ul>
<li>MVC 是后端的分层开发概念； MVVM是前端视图层的概念，主要关注于 视图层分离，也就是说：MVVM把前端的视图层，分为了三部分 Model, View , VM ViewModel</li>
<li>m   model  模型<ul>
<li>数据层   Vue  中 数据层 都放在 data 里面</li>
</ul>
</li>
<li>v   view     视图   <ul>
<li>Vue  中  view      即 我们的HTML页面  </li>
</ul>
</li>
<li>vm   （view-model）     控制器     将数据和视图层建立联系      <ul>
<li>vm 即  Vue 的实例  就是 vm  </li>
</ul>
</li>
</ul>
<h2 id="事件绑定"><a href="#事件绑定" class="headerlink" title="事件绑定"></a>事件绑定</h2><h3 id="v-on"><a href="#v-on" class="headerlink" title="v-on"></a>v-on</h3><ul>
<li>用来绑定事件的</li>
<li>形式如：v-on:click  缩写为 @click;</li>
</ul>
<img src="http://helloxx.cn/@click.png" srcset="/myblog/img/loading.gif"  width="90%">

<h3 id="v-on事件函数中传入参数"><a href="#v-on事件函数中传入参数" class="headerlink" title="v-on事件函数中传入参数"></a>v-on事件函数中传入参数</h3><pre><code class="html">
&lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
        &lt;div&gt;{{num}}&lt;/div&gt;
        &lt;div&gt;
            &lt;!-- 如果事件直接绑定函数名称，那么默认会传递事件对象作为事件函数的第一个参数 --&gt;
            &lt;button v-on:click=&#39;handle1&#39;&gt;点击1&lt;/button&gt;
            &lt;!-- 2、如果事件绑定函数调用，那么事件对象必须作为最后一个参数显示传递，
                 并且事件对象的名称必须是$event 
            --&gt;
            &lt;button v-on:click=&#39;handle2(123, 456, $event)&#39;&gt;点击2&lt;/button&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    &lt;script type=&quot;text/javascript&quot; src=&quot;js/vue.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/javascript&quot;&gt;
        var vm = new Vue({
            el: &#39;#app&#39;,
            data: {
                num: 0
            },
            methods: {
                handle1: function(event) {
                    console.log(event.target.innerHTML)
                },
                handle2: function(p, p1, event) {
                    console.log(p, p1)
                    console.log(event.target.innerHTML)
                    this.num++;
                }
            }
        });
    &lt;/script&gt;</code></pre>
<h3 id="事件修饰符"><a href="#事件修饰符" class="headerlink" title="事件修饰符"></a>事件修饰符</h3><ul>
<li>在事件处理程序中调用 <code>event.preventDefault()</code> 或 <code>event.stopPropagation()</code> 是非常常见的需求。</li>
<li>Vue 不推荐我们操作DOM    为了解决这个问题，Vue.js 为 <code>v-on</code> 提供了<strong>事件修饰符</strong></li>
<li>修饰符是由点开头的指令后缀来表示的</li>
</ul>
<pre><code class="html">&lt;!-- 阻止单击事件继续传播(阻止冒泡) --&gt;
&lt;a v-on:click.stop=&quot;doThis&quot;&gt;&lt;/a&gt;

&lt;!-- 提交事件不再重载页面 --&gt;
&lt;form @click.prevent=&quot;onSubmit&quot;&gt;&lt;/form&gt;

&lt;!-- 修饰符可以串联   即阻止冒泡也阻止默认事件 --&gt;
&lt;a v-on:click.stop.prevent=&quot;doThat&quot;&gt;&lt;/a&gt;

&lt;!-- 只当在 event.target 是当前元素自身时触发处理函数 --&gt;
&lt;!-- 即事件不是从内部元素触发的 --&gt;
&lt;div v-on:click.self=&quot;doThat&quot;&gt;...&lt;/div&gt;
使用修饰符时，顺序很重要；相应的代码会以同样的顺序产生。因此，用 v-on:click.prevent.self 会阻止所有的点击，而 v-on:click.self.prevent 只会阻止对元素自身的点击。</code></pre>
<h3 id="按键修饰符"><a href="#按键修饰符" class="headerlink" title="按键修饰符"></a>按键修饰符</h3><ul>
<li>在做项目中有时会用到键盘事件，在监听键盘事件时，我们经常需要检查详细的按键。Vue 允许为 <code>v-on</code> 在监听键盘事件时添加按键修饰符</li>
</ul>
<pre><code class="html">&lt;!-- 只有在 `keyCode` 是 13 时调用 `vm.submit()` --&gt;
&lt;input v-on:keyup.13=&quot;submit&quot;&gt;

&lt;!-- -当点击enter 时调用 `vm.submit()` --&gt;
&lt;input v-on:keyup.enter=&quot;submit&quot;&gt;

&lt;!--当点击enter或者space时  时调用 `vm.alertMe()`   --&gt;
&lt;input type=&quot;text&quot; v-on:keyup.enter.space=&quot;alertMe&quot; &gt;

常用的按键修饰符
.enter =&gt;    enter键
.tab =&gt; tab键
.delete (捕获“删除”和“退格”按键) =&gt;  删除键
.esc =&gt; 取消键
.space =&gt;  空格键
.up =&gt;  上
.down =&gt;  下
.left =&gt;  左
.right =&gt;  右

&lt;script&gt;
    var vm = new Vue({
        el:&quot;#app&quot;,
        methods: {
              submit:function(){},
              alertMe:function(){},
        }
    })

&lt;/script&gt;</code></pre>
<h3 id="自定义按键修饰符别名"><a href="#自定义按键修饰符别名" class="headerlink" title="自定义按键修饰符别名"></a>自定义按键修饰符别名</h3><ul>
<li>在Vue中可以通过<code>config.keyCodes</code>自定义按键修饰符别名</li>
</ul>
<pre><code class="html">&lt;div id=&quot;app&quot;&gt;
    预先定义了keycode 116（即F5）的别名为f5，因此在文字输入框中按下F5，会触发prompt方法
    &lt;input type=&quot;text&quot; v-on:keydown.f5=&quot;prompt()&quot;&gt;
&lt;/div&gt;

&lt;script&gt;

    Vue.config.keyCodes.f5 = 116;

    let app = new Vue({
        el: &#39;#app&#39;,
        methods: {
            prompt: function() {
                alert(&#39;我是 F5！&#39;);
            }
        }
    });
&lt;/script&gt;</code></pre>
<h3 id="v-bind"><a href="#v-bind" class="headerlink" title="v-bind"></a>v-bind</h3><ul>
<li>v-bind 指令被用来响应地更新 HTML 属性</li>
<li>v-bind:href    可以缩写为    :href</li>
</ul>
<pre><code class="html">&lt;!-- 绑定一个属性 --&gt;
&lt;img v-bind:src=&quot;imageSrc&quot;&gt;

&lt;!-- 缩写 --&gt;
&lt;img :src=&quot;imageSrc&quot;&gt;</code></pre>
<pre><code class="js">  v-model的低层实现原理分析 
  &lt;input v-bind:value=&quot;msg&quot; v-on:input=&quot;msg=$event.target.value&quot;&gt;</code></pre>
<h4 id="绑定对象"><a href="#绑定对象" class="headerlink" title="绑定对象"></a>绑定对象</h4><ul>
<li>我们可以给v-bind:class 一个对象，以动态地切换class。</li>
<li>注意：v-bind:class指令可以与普通的class特性共存</li>
</ul>
<pre><code class="html">1、 v-bind 中支持绑定一个对象 
    如果绑定的是一个对象 则 键为 对应的类名  值 为对应data中的数据 
&lt;!-- 
    HTML最终渲染为 &lt;ul class=&quot;box textColor textSize&quot;&gt;&lt;/ul&gt;
    注意：
        textColor，textSize  对应的渲染到页面上的CSS类名    
        isColor，isSize  对应vue data中的数据  如果为true 则对应的类名 渲染到页面上 
        当 isColor 和 isSize 变化时，class列表将相应的更新，
        例如，将isSize改成false，
        class列表将变为 &lt;ul class=&quot;box textColor&quot;&gt;&lt;/ul&gt;
--&gt;

&lt;ul class=&quot;box&quot; v-bind:class=&quot;{textColor:isColor, textSize:isSize}&quot;&gt;
    &lt;li&gt;学习Vue&lt;/li&gt;
    &lt;li&gt;学习Node&lt;/li&gt;
    &lt;li&gt;学习React&lt;/li&gt;
&lt;/ul&gt;
  &lt;div v-bind:style=&quot;{color:activeColor,fontSize:activeSize}&quot;&gt;对象语法&lt;/div&gt;

&lt;sript&gt;
var vm= new Vue({
    el:&#39;.box&#39;,
    data:{
        isColor:true,
        isSize:true，
        activeColor:&quot;red&quot;,
        activeSize:&quot;25px&quot;,
    }
})
&lt;/sript&gt;
&lt;style&gt;

    .box{
        border:1px dashed #f0f;
    }
    .textColor{
        color:#f00;
        background-color:#eef;
    }
    .textSize{
        font-size:30px;
        font-weight:bold;
    }
&lt;/style&gt;</code></pre>
<h4 id="绑定class"><a href="#绑定class" class="headerlink" title="绑定class"></a>绑定class</h4><pre><code class="html">对象语法
&lt;div v-bind:class=&quot;{ active: isActive }&quot;&gt;&lt;/div&gt; //一般isActive都是布尔值
数组语法
&lt;div v-bind:class=&quot;[activeClass, errorClass]&quot;&gt;&lt;/div&gt;</code></pre>
<pre><code class="html">2、  v-bind 中支持绑定一个数组    数组中classA和 classB 对应为data中的数据

这里的classA  对用data 中的  classA
这里的classB  对用data 中的  classB
&lt;ul class=&quot;box&quot; :class=&quot;[classA, classB]&quot;&gt;
    &lt;li&gt;学习Vue&lt;/li&gt;
    &lt;li&gt;学习Node&lt;/li&gt;
    &lt;li&gt;学习React&lt;/li&gt;
&lt;/ul&gt;
&lt;script&gt;
var vm= new Vue({
    el:&#39;.box&#39;,
    data:{
        classA:&#39;textColor&#39;,
        classB:&#39;textSize&#39;
    }
})
&lt;/script&gt;
&lt;style&gt;
    .box{
        border:1px dashed #f0f;
    }
    .textColor{
        color:#f00;
        background-color:#eef;
    }
    .textSize{
        font-size:30px;
        font-weight:bold;
    }
&lt;/style&gt;</code></pre>
<h4 id="绑定对象和绑定数组-的区别"><a href="#绑定对象和绑定数组-的区别" class="headerlink" title="绑定对象和绑定数组 的区别"></a>绑定对象和绑定数组 的区别</h4><ul>
<li>绑定对象的时候 对象的属性 即要渲染的类名 对象的属性值对应的是 data 中的数据 </li>
<li>绑定数组的时候数组里面存的是data 中的数据 </li>
</ul>
<h4 id="绑定style"><a href="#绑定style" class="headerlink" title="绑定style"></a>绑定style</h4><pre><code class="html"> &lt;div v-bind:style=&quot;styleObject&quot;&gt;绑定样式对象&lt;/div&gt;&#39;

&lt;!-- CSS 属性名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case，记得用单引号括起来)    --&gt;
 &lt;div v-bind:style=&quot;{ color: activeColor, fontSize: fontSize,background:&#39;red&#39; }&quot;&gt;内联样式&lt;/div&gt;

&lt;!--组语法可以将多个样式对象应用到同一个元素 --&gt;
&lt;div v-bind:style=&quot;[styleObj1, styleObj2]&quot;&gt;&lt;/div&gt;


&lt;script&gt;
    new Vue({
      el: &#39;#app&#39;,
      data: {
        styleObject: {
          color: &#39;green&#39;,
          fontSize: &#39;30px&#39;,
          background:&#39;red&#39;
        }，
        activeColor: &#39;green&#39;,
           fontSize: &quot;30px&quot;
      },
      styleObj1: {
             color: &#39;red&#39;
       },
       styleObj2: {
            fontSize: &#39;30px&#39;
       }

&lt;/script&gt;</code></pre>
<h3 id="分支结构"><a href="#分支结构" class="headerlink" title="分支结构"></a>分支结构</h3><h4 id="v-if-使用场景"><a href="#v-if-使用场景" class="headerlink" title="v-if 使用场景"></a>v-if 使用场景</h4><ul>
<li>1- 多个元素 通过条件判断展示或者隐藏某个元素。或者多个元素</li>
<li>2- 进行两个视图之间的切换 </li>
</ul>
<pre><code class="html">&lt;div id=&quot;app&quot;&gt;
    &lt;!--  判断是否加载，如果为真，就加载，否则不加载--&gt;
    &lt;span v-if=&quot;flag&quot;&gt;
        如果flag为true则显示,false不显示!
    &lt;/span&gt;
&lt;/div&gt;
&lt;script&gt;
    var vm = new Vue({
        el:&quot;#app&quot;,
        data:{
            flag:true
        }
    })
&lt;/script&gt;
----------------------------------------------------------
&lt;div v-if=&quot;type === &#39;A&#39;&quot;&gt;
    A
&lt;/div&gt;
&lt;!-- v-else-if紧跟在v-if或v-else-if之后   表示v-if条件不成立时执行--&gt;
&lt;div v-else-if=&quot;type === &#39;B&#39;&quot;&gt;
    B
&lt;/div&gt;
&lt;div v-else-if=&quot;type === &#39;C&#39;&quot;&gt;
    C
&lt;/div&gt;
&lt;!-- v-else紧跟在v-if或v-else-if之后--&gt;
&lt;div v-else&gt;
    Not A/B/C
&lt;/div&gt;
&lt;script&gt;
    new Vue({
        el: &#39;#app&#39;,
        data: {
            type: &#39;C&#39;
        }
    })
&lt;/script&gt;</code></pre>
<h4 id="v-show-和-v-if的区别"><a href="#v-show-和-v-if的区别" class="headerlink" title="v-show 和 v-if的区别"></a>v-show 和 v-if的区别</h4><ul>
<li>v-show本质就是标签display设置为none，控制隐藏<ul>
<li>v-show只编译一次，后面其实就是控制css，而v-if不停的销毁和创建，故v-show性能更好一点。</li>
</ul>
</li>
<li>v-if是动态的向DOM树内添加或者删除DOM元素<ul>
<li>v-if切换有一个局部编译/卸载的过程，切换过程中合适地销毁和重建内部的事件监听和子组件</li>
</ul>
</li>
</ul>
<h3 id="循环结构"><a href="#循环结构" class="headerlink" title="循环结构"></a>循环结构</h3><h4 id="v-for"><a href="#v-for" class="headerlink" title="v-for"></a>v-for</h4><ul>
<li>用于循环的数组里面的值可以是对象，也可以是普通元素  </li>
<li>数组只能使用list内置方法，如push pop shift unshift ，不能使用下标的方法去做增删改查操作 ，因为页面不会变化</li>
</ul>
<pre><code class="html">&lt;ul id=&quot;example-1&quot;&gt;
    &lt;!-- 循环结构-遍历数组  
item 是我们自己定义的一个名字  代表数组里面的每一项  
items对应的是 data中的数组--&gt;
    &lt;li v-for=&quot;item in items&quot;&gt;
        {{ item.message }}
    &lt;/li&gt;
    &lt;li v-for=&quot;(item, key, index) of userInfo&quot;&gt;
        {{ item }}--{{ key }}--{{ index }} //key代表键，index则是下标
    &lt;/li&gt;
&lt;/ul&gt;
&lt;script&gt;
    new Vue({
        el: &#39;#example-1&#39;,
        data: {
            items: [
                { message: &#39;Foo&#39; },
                { message: &#39;Bar&#39; }
            ]，
            userInfo: {
            name: &#39;dell&#39;,
            age: 28,
            gender: &#39;male&#39;,
            salary: &#39;secret&#39;}
    }
            })
&lt;/script&gt;</code></pre>
<ul>
<li><strong>不推荐</strong>同时使用 <code>v-if</code> 和 <code>v-for</code></li>
<li>当 <code>v-if</code> 与 <code>v-for</code> 一起使用时，<code>v-for</code> 具有比 <code>v-if</code> 更高的优先级。</li>
</ul>
<pre><code class="html">&lt;!--  循环结构-遍历对象
v 代表   对象的value
k  代表对象的 键 
i  代表索引    
---&gt; 
&lt;div v-if=&#39;v==13&#39; v-for=&#39;(v,k,i) in obj&#39;&gt;{{v + '---' + k + '---' + i}}&lt;/div&gt;
&lt;script&gt;
    new Vue({
        el: &#39;#example-1&#39;,
        data: {
            items: [
                { message: &#39;Foo&#39; },
                { message: &#39;Bar&#39; }
            ]，
            obj: {
            uname: &#39;zhangsan&#39;,
            age: 13,
            gender: &#39;female&#39;
        }
    }
            })
&lt;/script&gt;</code></pre>
<ul>
<li>key 的作用<ul>
<li><strong>key来给每个节点做一个唯一标识</strong></li>
<li><strong>key的作用主要是为了高效的更新虚拟DOM</strong></li>
</ul>
</li>
</ul>
<pre><code class="html">&lt;ul&gt;
  &lt;li v-for=&quot;item in items&quot; :key=&quot;item.id&quot;&gt;...&lt;/li&gt;
&lt;/ul&gt;
</code></pre>
<h3 id="案例选项卡"><a href="#案例选项卡" class="headerlink" title="案例选项卡"></a>案例选项卡</h3><p>1、 HTML 结构</p>
<pre><code class="html">&lt;div id=&quot;app&quot;&gt;
    &lt;div class=&quot;tab&quot;&gt;
        &lt;!--  tab栏  --&gt;
        &lt;ul&gt;
            &lt;li class=&quot;active&quot;&gt;apple&lt;/li&gt;
            &lt;li class=&quot;&quot;&gt;orange&lt;/li&gt;
            &lt;li class=&quot;&quot;&gt;lemon&lt;/li&gt;
        &lt;/ul&gt;
        &lt;!--  对应显示的图片 --&gt;
        &lt;div class=&quot;current&quot;&gt;&lt;img src=&quot;img/apple.png&quot;&gt;&lt;/div&gt;
        &lt;div class=&quot;&quot;&gt;&lt;img src=&quot;img/orange.png&quot;&gt;&lt;/div&gt;
        &lt;div class=&quot;&quot;&gt;&lt;img src=&quot;img/lemon.png&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;</code></pre>
<p>2、 提供的数据</p>
<pre><code class="js">list: [{
    id: 1,
    title: &#39;apple&#39;,
    path: &#39;img/apple.png&#39;
}, {
    id: 2,
    title: &#39;orange&#39;,
    path: &#39;img/orange.png&#39;
}, {
    id: 3,
    title: &#39;lemon&#39;,
    path: &#39;img/lemon.png&#39;
}]</code></pre>
<p>3、 把数据渲染到页面</p>
<ul>
<li><p>把tab栏 中的数替换到页面上</p>
<ul>
<li>把 data 中 title  利用 v-for 循环渲染到页面上 </li>
<li>把 data 中 path利用 v-for 循环渲染到页面上 </li>
</ul>
<pre><code class="html">&lt;div id=&quot;app&quot;&gt;
    &lt;div class=&quot;tab&quot;&gt;  
        &lt;ul&gt;
            &lt;!--  
1、绑定key的作用 提高Vue的性能 
2、 key 需要是唯一的标识 所以需要使用id， 也可以使用index ，
index 也是唯一的 
3、 item 是 数组中对应的每一项  
4、 index 是 每一项的 索引
--&gt;
            &lt;li :key=&#39;item.id&#39; v-for=&#39;(item,index) in list&#39;&gt;{{item.title}}&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div  :key=&#39;item.id&#39; v-for=&#39;(item, index) in list&#39;&gt;
            &lt;!-- :  是 v-bind 的简写   绑定属性使用 v-bind --&gt;
            &lt;img :src=&quot;item.path&quot;&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;script&gt;
    new  Vue({
        //  指定 操作元素 是 id 为app 的 
        el: &#39;#app&#39;,
        data: {
            list: [{
                id: 1,
                title: &#39;apple&#39;,
                path: &#39;img/apple.png&#39;
            }, {
                id: 2,
                title: &#39;orange&#39;,
                path: &#39;img/orange.png&#39;
            }, {
                id: 3,
                title: &#39;lemon&#39;,
                path: &#39;img/lemon.png&#39;
            }]
        }
    })

&lt;/script&gt;</code></pre>
</li>
</ul>
<p>4、 给每一个tab栏添加事件,并让选中的高亮</p>
<ul>
<li><p>4.1 、让默认的第一项tab栏高亮</p>
<ul>
<li>tab栏高亮 通过添加类名active 来实现   （CSS  active 的样式已经提前写好）<ul>
<li>在data 中定义一个 默认的  索引 currentIndex  为  0 </li>
<li>给第一个li 添加 active 的类名  <ul>
<li>通过动态绑定class 来实现   第一个li 的索引为 0     和 currentIndex   的值刚好相等</li>
<li>currentIndex     ===  index  如果相等  则添加类名 active  否则 添加 空类名</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><p>4.2 、让默认的第一项tab栏对应的div 显示 </p>
<ul>
<li>实现思路 和 第一个 tab 实现思路一样  只不过 这里控制第一个div 显示的类名是 current</li>
</ul>
<pre><code class="html">&lt;ul&gt;
    &lt;!-- 动态绑定class   有 active   类名高亮  无 active   不高亮--&gt;
    &lt;li  :class=&#39;currentIndex==index?&quot;active&quot;:&quot;&quot;&#39;
        :key=&#39;item.id&#39; v-for=&#39;(item,index) in list&#39;
        &gt;{{item.title}}&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- 动态绑定class   有 current  类名显示  无 current  隐藏--&gt;
&lt;div :class=&#39;currentIndex==index?&quot;current&quot;:&quot;&quot;&#39; 

     :key=&#39;item.id&#39; v-for=&#39;(item, index) in list&#39;&gt;
    &lt;!-- :  是 v-bind 的简写   绑定属性使用 v-bind --&gt;
    &lt;img :src=&quot;item.path&quot;&gt;
&lt;/div&gt;

&lt;script&gt;
    new  Vue({
        el: &#39;#app&#39;,
        data: {
            currentIndex: 0, // 选项卡当前的索引  默认为 0  
            list: [{
                id: 1,
                title: &#39;apple&#39;,
                path: &#39;img/apple.png&#39;
            }, {
                id: 2,
                title: &#39;orange&#39;,
                path: &#39;img/orange.png&#39;
            }, {
                id: 3,
                title: &#39;lemon&#39;,
                path: &#39;img/lemon.png&#39;
            }]
        }
    })

&lt;/script&gt;</code></pre>
</li>
<li><p>4.3 、点击每一个tab栏 当前的高亮 其他的取消高亮 </p>
<ul>
<li><p>给每一个li添加点击事件    </p>
</li>
<li><p>让当前的索引 index  和  当前 currentIndex 的  值 进项比较 </p>
</li>
<li><p>如果相等 则当前li  添加active 类名 当前的 li 高亮  当前对应索引的 div 添加 current 当前div 显示 其他隐藏</p>
<pre><code class="html">&lt;div id=&quot;app&quot;&gt;
    &lt;div class=&quot;tab&quot;&gt;
        &lt;ul&gt;
            &lt;!--  通过v-on 添加点击事件   需要把当前li 的索引传过去 
--&gt;
            &lt;li v-on:click=&#39;change(index)&#39;                               
                :class=&#39;currentIndex==index?&quot;active&quot;:&quot;&quot;&#39;                   
                :key=&#39;item.id&#39; 
                v-for=&#39;(item,index) in list&#39;&gt;{{item.title}}&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div :class=&#39;currentIndex==index?&quot;current&quot;:&quot;&quot;&#39; 
             :key=&#39;item.id&#39; v-for=&#39;(item, index) in list&#39;&gt;
            &lt;img :src=&quot;item.path&quot;&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;script&gt;
    new  Vue({
        el: &#39;#app&#39;,
        data: {
            currentIndex: 0, // 选项卡当前的索引  默认为 0  
            list: [{
                id: 1,
                title: &#39;apple&#39;,
                path: &#39;img/apple.png&#39;
            }, {
                id: 2,
                title: &#39;orange&#39;,
                path: &#39;img/orange.png&#39;
            }, {
                id: 3,
                title: &#39;lemon&#39;,
                path: &#39;img/lemon.png&#39;
            }]
        },
        methods: {
            change: function(index) {
                // 通过传入过来的索引来让当前的  currentIndex  和点击的index 值 相等 
                //  从而实现 控制类名    
                this.currentIndex = index;
            }
        }

    })

&lt;/script&gt;</code></pre>
</li>
</ul>
</li>
</ul>
<h1 id="day02"><a href="#day02" class="headerlink" title="day02"></a>day02</h1><h2 id="Vue常用特性"><a href="#Vue常用特性" class="headerlink" title="Vue常用特性"></a>Vue常用特性</h2><h3 id="表单基本操作"><a href="#表单基本操作" class="headerlink" title="表单基本操作"></a>表单基本操作</h3><ul>
<li><p>获取单选框中的值</p>
<ul>
<li>通过v-model</li>
</ul>
<pre><code class="html">&lt;!--
1、 两个单选框需要同时通过v-model 双向绑定 一个值 
2、 每一个单选框必须要有value属性  且value 值不能一样 
3、 当某一个单选框选中的时候 v-model  会将当前的 value值 改变 data 中的 数据
gender 的值就是选中的值，我们只需要实时监控他的值就可以了
--&gt;
&lt;input type=&quot;radio&quot; id=&quot;male&quot; value=&quot;1&quot; v-model=&#39;gender&#39;&gt;
&lt;label for=&quot;male&quot;&gt;男&lt;/label&gt;
&lt;input type=&quot;radio&quot; id=&quot;female&quot; value=&quot;2&quot; v-model=&#39;gender&#39;&gt;
&lt;label for=&quot;female&quot;&gt;女&lt;/label&gt;
&lt;script&gt;
    new Vue({
        data: {
            // 默认会让当前的 value 值为 2 的单选框选中
            gender: 2,  
        },
    })
&lt;/script&gt;</code></pre>
</li>
<li><p>获取复选框中的值</p>
<ul>
<li>通过v-model</li>
<li>和获取单选框中的值一样 </li>
<li>复选框 <code>checkbox</code> 这种的组合时   data 中的 hobby 我们要定义成数组 否则无法实现多选</li>
</ul>
<pre><code class="html">&lt;!-- 
1、 复选框需要同时通过v-model 双向绑定 一个值 
2、 每一个复选框必须要有value属性  且value 值不能一样 
3、 当某一个单选框选中的时候 v-model  会将当前的 value值 改变 data 中的 数据
hobby 的值就是选中的值，我们只需要实时监控他的值就可以了
--&gt;
&lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
        &lt;span&gt;爱好：&lt;/span&gt;
        &lt;input type=&quot;checkbox&quot; id=&quot;ball&quot; value=&quot;1&quot; v-model=&#39;hobby&#39;&gt;
        &lt;label for=&quot;ball&quot;&gt;篮球&lt;/label&gt;
        &lt;input type=&quot;checkbox&quot; id=&quot;sing&quot; value=&quot;2&quot; v-model=&#39;hobby&#39;&gt;
        &lt;label for=&quot;sing&quot;&gt;唱歌&lt;/label&gt;
        &lt;input type=&quot;checkbox&quot; id=&quot;code&quot; value=&quot;3&quot; v-model=&#39;hobby&#39;&gt;
        &lt;label for=&quot;code&quot;&gt;写代码&lt;/label&gt;
    &lt;/div&gt;
    &lt;script&gt;
        var vm = new Vue({
            el:&#39;#app&#39;,
            data: {
                // 默认会让当前的 value 值为 2 和 3 的复选框选中
                hobby: [&#39;2&#39;, &#39;3&#39;],
            },
        })
    &lt;/script&gt;
&lt;/body&gt;</code></pre>
</li>
<li><p>获取下拉框和文本框中的值</p>
<ul>
<li>通过v-model</li>
</ul>
<pre><code class="html">&lt;div id=&quot;app&quot;&gt;
    &lt;span&gt;职业：&lt;/span&gt;
    &lt;!--
1、 需要给select  通过v-model 双向绑定 一个值 
2、 每一个option  必须要有value属性  且value 值不能一样 
3、 当某一个option选中的时候 v-model  会将当前的 value值 改变 data 中的 数据
occupation 的值就是选中的值，我们只需要实时监控他的值就可以了
--&gt;
    &lt;!-- multiple  多选 --&gt;
    &lt;select v-model=&#39;occupation&#39; multiple&gt;
        &lt;option value=&quot;0&quot;&gt;请选择职业...&lt;/option&gt;
        &lt;option value=&quot;1&quot;&gt;教师&lt;/option&gt;
        &lt;option value=&quot;2&quot;&gt;软件工程师&lt;/option&gt;
        &lt;option value=&quot;3&quot;&gt;律师&lt;/option&gt;
    &lt;/select&gt;
    &lt;!-- textarea 是 一个双标签   不需要绑定value 属性的  --&gt;
    &lt;textarea v-model=&#39;desc&#39;&gt;&lt;/textarea&gt;
&lt;/div&gt;
&lt;script&gt;
    var vm = new Vue({
        el:&#39;#app&#39;,
        data: {
            // 默认会让当前的 value 值为 2 和 3 的下拉框选中
            occupation: [&#39;2&#39;, &#39;3&#39;],
            desc: &#39;nihao&#39;
        },
    })
&lt;/script&gt;</code></pre>
</li>
</ul>
<h3 id="表单修饰符"><a href="#表单修饰符" class="headerlink" title="表单修饰符"></a>表单修饰符</h3><ul>
<li><p>.number  转换为数值</p>
<ul>
<li>注意点：    </li>
<li>当开始输入非数字的字符串时，因为Vue无法将字符串转换成数值</li>
<li>所以属性值将实时更新成相同的字符串。即使后面输入数字，也将被视作字符串。</li>
</ul>
</li>
<li><p>.trim  自动过滤用户输入的首尾空白字符</p>
<ul>
<li>只能去掉首尾的 不能去除中间的空格</li>
</ul>
</li>
<li><p>.lazy   将input事件切换成change事件</p>
<ul>
<li>.lazy 修饰符延迟了同步更新属性值的时机。即将原本绑定在 input 事件的同步逻辑转变为绑定在 change 事件上在失去焦点 或者 按下回车键时才更新</li>
</ul>
<pre><code class="html">&lt;!-- 自动将用户的输入值转为数值类型 --&gt;
&lt;input v-model.number=&quot;age&quot; type=&quot;number&quot;&gt;

&lt;!--自动过滤用户输入的首尾空白字符   --&gt;
&lt;input v-model.trim=&quot;msg&quot;&gt;

&lt;!-- 在change时而非input时更新 --&gt;
&lt;input v-model.lazy=&quot;msg&quot; &gt;//懒加载</code></pre>
</li>
</ul>
<h3 id="自定义指令"><a href="#自定义指令" class="headerlink" title="自定义指令"></a>自定义指令</h3><ul>
<li>内置指令不能满足我们特殊的需求</li>
<li>Vue允许我们自定义指令</li>
</ul>
<h4 id="Vue-directive-注册全局指令"><a href="#Vue-directive-注册全局指令" class="headerlink" title="Vue.directive  注册全局指令"></a>Vue.directive  注册全局指令</h4><pre><code class="html">&lt;!-- 
使用自定义的指令，只需在对用的元素中，加上&#39;v-&#39;的前缀形成类似于内部指令&#39;v-if&#39;，&#39;v-text&#39;的形式。 
--&gt;
&lt;input type=&quot;text&quot; v-focus&gt;
&lt;script&gt;
    // 注意点： 
    //   1、 在自定义指令中  如果以驼峰命名的方式定义 如  Vue.directive(&#39;focusA&#39;,function(){}) 
    //   2、 在HTML中使用的时候 只能通过 v-focus-a 来使用 
    // 注册一个全局自定义指令 v-focus
    Vue.directive(&#39;focus&#39;, {
        // 当绑定元素插入到 DOM 中。 其中 el为dom元素
        inserted: function (el) {
            // 聚焦元素
            el.focus();
        }
    });
    new Vue({
        el:&#39;#app&#39;
    });
&lt;/script&gt;</code></pre>
<h4 id="Vue-directive-注册全局指令-带参数"><a href="#Vue-directive-注册全局指令-带参数" class="headerlink" title="Vue.directive  注册全局指令 带参数"></a>Vue.directive  注册全局指令 带参数</h4><pre><code class="html">&lt;input type=&quot;text&quot; v-color=&#39;msg&#39;&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
    /*自定义指令-带参数
      bind - 只调用一次，在指令第一次绑定到元素上时候调用*/
    Vue.directive(&#39;color&#39;, {
        // bind声明周期, 只调用一次，指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置
        // el 为当前自定义指令的DOM元素  
        // binding 为自定义的函数形参   通过自定义属性传递过来的值 存在 binding.value 里面
        bind: function(el, binding){
            // 根据指令的参数设置背景色
            // console.log(binding.value.color)
            el.style.backgroundColor = binding.value.color;
        }
    });
    var vm = new Vue({
        el: &#39;#app&#39;,
        data: {
            msg: {
                color: &#39;blue&#39;
            }
        }
    });
&lt;/script&gt;</code></pre>
<h4 id="自定义指令局部指令"><a href="#自定义指令局部指令" class="headerlink" title="自定义指令局部指令"></a>自定义指令局部指令</h4><ul>
<li>局部指令，需要定义在  directives 的选项   用法和全局用法一样 </li>
<li>局部指令只能在当前组件里面使用</li>
<li>当全局指令和局部指令同名时以局部指令为准</li>
</ul>
<pre><code class="html">&lt;input type=&quot;text&quot; v-color=&#39;msg&#39;&gt;
&lt;input type=&quot;text&quot; v-focus&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
    /*
      自定义指令-局部指令
    */
    var vm = new Vue({
        el: &#39;#app&#39;,
        data: {
            msg: {
                color: &#39;red&#39;
            }
        },
        //局部指令，需要定义在  directives 的选项
        directives: {
            color: {
                bind: function(el, binding){
                    el.style.backgroundColor = binding.value.color;
                }
            },
            focus: {
                inserted: function(el) {
                    el.focus();
                }
            }
        }
    });
&lt;/script&gt;</code></pre>
<h3 id="计算属性-computed"><a href="#计算属性-computed" class="headerlink" title="计算属性   computed"></a>计算属性   computed</h3><ul>
<li>模板中放入太多的逻辑会让模板过重且难以维护  使用计算属性可以让模板更加的简洁</li>
<li><strong>计算属性是基于它们的响应式依赖进行缓存的</strong></li>
<li>computed比较适合对多个变量或者对象进行处理后返回一个结果值，也就是数多个变量中的某一个值发生了变化则我们监控的这个值也就会发生变化</li>
</ul>
<pre><code class="html">&lt;div id=&quot;app&quot;&gt;
    &lt;!--当多次调用 reverseString  的时候 
只要里面的 num 值不改变 他会把第一次计算的结果直接返回
直到data 中的num值改变 计算属性才会重新发生计算--&gt;
    &lt;div&gt;{{reverseString}}&lt;/div&gt;
    &lt;div&gt;{{reverseString}}&lt;/div&gt;
    &lt;!-- 调用methods中的方法的时候  他每次会重新调用 --&gt;
    &lt;div&gt;{{reverseMessage()}}&lt;/div&gt;
    &lt;div&gt;{{reverseMessage()}}&lt;/div&gt;
&lt;/div&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
    //计算属性与方法的区别:计算属性是基于依赖进行缓存的，而方法不缓存
    var vm = new Vue({
        el: &#39;#app&#39;,
        data: {
            msg: &#39;Nihao&#39;,
            num: 100
        },
        methods: {
            reverseMessage: function(){
                console.log(&#39;methods&#39;)
                return this.msg.split(&#39;&#39;).reverse().join(&#39;&#39;);
            }
        },
        //computed  属性 定义 和 data 已经 methods 平级 
        computed: {
            //  reverseString   这个是我们自己定义的名字 
            reverseString: function(){
                console.log(&#39;computed&#39;)
                var total = 0;
                //  当data 中的 num 的值改变的时候  reverseString  会自动发生计算  
                for(var i=0;i&lt;=this.num;i++){
                    total += i;
                }
                // 这里一定要有return 否则 调用 reverseString 的 时候无法拿到结果    
                return total;
            }
        }
    });
&lt;/script&gt;</code></pre>
<h3 id="侦听器-watch"><a href="#侦听器-watch" class="headerlink" title="侦听器   watch"></a>侦听器   watch</h3><ul>
<li>使用watch来响应数据的变化</li>
<li>一般用于异步或者开销较大的操作</li>
<li>watch 中的属性 一定是data 中 已经存在的数据 </li>
<li><strong>当需要监听一个对象的改变时，普通的watch方法无法监听到对象内部属性的改变，只有data中的数据才能够监听到变化，此时就需要deep属性对对象进行深度监听</strong></li>
</ul>
<pre><code class="html">&lt;div id=&quot;app&quot;&gt;
    &lt;div&gt;
        &lt;span&gt;名：&lt;/span&gt;
        &lt;span&gt;
            &lt;input type=&quot;text&quot; v-model=&#39;firstName&#39;&gt;
        &lt;/span&gt;
    &lt;/div&gt;
    &lt;div&gt;
        &lt;span&gt;姓：&lt;/span&gt;
        &lt;span&gt;
            &lt;input type=&quot;text&quot; v-model=&#39;lastName&#39;&gt;
        &lt;/span&gt;
    &lt;/div&gt;
    &lt;div&gt;{{fullName}}&lt;/div&gt;
&lt;/div&gt;

&lt;script type=&quot;text/javascript&quot;&gt;
    //侦听器
    var vm = new Vue({
        el: &#39;#app&#39;,
        data: {
            firstName: &#39;Jim&#39;,
            lastName: &#39;Green&#39;,
            // fullName: &#39;Jim Green&#39;
        },
        //watch  属性 定义 和 data 已经 methods 平级 
        watch: {
            //   注意：  这里firstName  对应着data 中的 firstName 
            //   当 firstName 值 改变的时候  会自动触发 watch
            firstName: function(val) {
                this.fullName = val + &#39; &#39; + this.lastName;
            },
            //   注意：  这里 lastName 对应着data 中的 lastName 
            lastName: function(val) {
                this.fullName = this.firstName + &#39; &#39; + val;
            }
        }
    });
&lt;/script&gt;</code></pre>
<h3 id="过滤器"><a href="#过滤器" class="headerlink" title="过滤器"></a>过滤器</h3><ul>
<li>Vue.js允许自定义过滤器，可被用于一些常见的文本格式化。</li>
<li>过滤器可以用在两个地方：双花括号插值和v-bind表达式。</li>
<li>过滤器应该被添加在JavaScript表达式的尾部，由“管道”符号指示</li>
<li>支持级联操作</li>
<li>过滤器不改变真正的<code>data</code>，而只是改变渲染的结果，并返回过滤后的版本</li>
<li>全局注册时是filter，没有s的。而局部过滤器是filters，是有s的</li>
</ul>
<pre><code class="html">&lt;div id=&quot;app&quot;&gt;
    &lt;input type=&quot;text&quot; v-model=&#39;msg&#39;&gt;
    &lt;!-- upper 被定义为接收单个参数的过滤器函数，表达式  msg  的值将作为参数传入到函数中 --&gt;
    &lt;div&gt;{{msg | upper}}&lt;/div&gt;
    &lt;!--  
支持级联操作
upper  被定义为接收单个参数的过滤器函数，表达式msg 的值将作为参数传入到函数中。
然后继续调用同样被定义为接收单个参数的过滤器 lower ，将upper 的结果传递到lower中
--&gt;
    &lt;div&gt;{{msg | upper | lower}}&lt;/div&gt;
    &lt;div :abc=&#39;msg | upper&#39;&gt;测试数据&lt;/div&gt;
&lt;/div&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
    //  lower  为全局过滤器     
    Vue.filter(&#39;lower&#39;, function(val) {
        return val.charAt(0).toLowerCase() + val.slice(1);
    });
    var vm = new Vue({
        el: &#39;#app&#39;,
        data: {
            msg: &#39;&#39;
        },
        //filters  属性 定义 和 data 已经 methods 平级 
        //  定义filters 中的过滤器为局部过滤器 
        filters: {
            //   upper  自定义的过滤器名字 
            //    upper 被定义为接收单个参数的过滤器函数，表达式  msg  的值将作为参数传入到函数中
            upper: function(val) {
                //  过滤器中一定要有返回值 这样外界使用过滤器的时候才能拿到结果
                return val.charAt(0).toUpperCase() + val.slice(1);
            }
        }
    });
&lt;/script&gt;</code></pre>
<h4 id="过滤器中传递参数"><a href="#过滤器中传递参数" class="headerlink" title="过滤器中传递参数"></a>过滤器中传递参数</h4><pre><code class="html">    &lt;div id=&quot;box&quot;&gt;
        &lt;!--
            filterA 被定义为接收三个参数的过滤器函数。
              其中 message 的值作为第一个参数，
            普通字符串 &#39;arg1&#39; 作为第二个参数，表达式 arg2 的值作为第三个参数。
        --&gt;
        {{ message | filterA('arg1', 'arg2') }}
    &lt;/div&gt;
    &lt;script&gt;
        // 在过滤器中 第一个参数 对应的是  管道符前面的数据   n  此时对应 message
        // 第2个参数  a 对应 实参  arg1 字符串
        // 第3个参数  b 对应 实参  arg2 字符串
        Vue.filter(&#39;filterA&#39;,function(n,a,b){
            if(n&lt;10){
                return n+a;
            }else{
                return n+b;
            }
        });

        new Vue({
            el:&quot;#box&quot;,
            data:{
                message: &quot;哈哈哈&quot;
            }
        })

    &lt;/script&gt;</code></pre>
<h3 id="生命周期"><a href="#生命周期" class="headerlink" title="生命周期"></a>生命周期</h3><p>  Vue实例的产生过程 </p>
<ol>
<li>beforeCreate 在实例初始化之后，数据观测和事件配置之前被调用。 </li>
<li>created 在实例创建完成后被立即调用。 </li>
<li>beforeMount 在挂载开始之前被调用。</li>
<li>mounted el被新创建的vm.$el替换，并挂载到实例上去之后调用该钩子。</li>
<li>beforeUpdate 数据更新时调用，发生在虚拟DOM打补丁之前。</li>
<li>updated 由于数据更改导致的虚拟DOM重新渲染和打补丁，在这之后会调用该钩子。 </li>
<li>beforeDestroy 实例销毁之前调用。 </li>
<li>destroyed 实例销毁后调用。 </li>
</ol>
<ul>
<li>事物从出生到死亡的过程</li>
<li>Vue实例从创建 到销毁的过程 ，这些过程中会伴随着一些函数的自调用。我们称这些函数为钩子函数</li>
</ul>
<p>常用的钩子函数</p>
<table>
<thead>
<tr>
<th>beforeCreate</th>
<th>在实例初始化之后，数据观测和事件配置之前被调用 此时data 和 methods 以及页面的DOM结构都没有初始化   什么都做不了</th>
</tr>
</thead>
<tbody><tr>
<td>created</td>
<td>在实例创建完成后被立即调用此时data 和 methods已经可以使用  但是页面还没有渲染出来</td>
</tr>
<tr>
<td>beforeMount</td>
<td>在挂载开始之前被调用   此时页面上还看不到真实数据 只是一个模板页面而已</td>
</tr>
<tr>
<td>mounted</td>
<td>el被新创建的<code>vm.$el</code>替换，并挂载到实例上去之后调用该钩子。  数据已经真实渲染到页面上  在这个钩子函数里面我们可以使用一些第三方的插件</td>
</tr>
<tr>
<td>beforeUpdate</td>
<td>数据更新时调用，发生在虚拟DOM打补丁之前。   页面上数据还是旧的</td>
</tr>
<tr>
<td>updated</td>
<td>由于数据更改导致的虚拟DOM重新渲染和打补丁，在这之后会调用该钩子。 页面上数据已经替换成最新的</td>
</tr>
<tr>
<td>beforeDestroy</td>
<td>实例销毁之前调用</td>
</tr>
<tr>
<td>destroyed</td>
<td>实例销毁后调用</td>
</tr>
</tbody></table>
<h3 id="数组变异方法"><a href="#数组变异方法" class="headerlink" title="数组变异方法"></a>数组变异方法</h3><ul>
<li>在 Vue 中，直接修改对象属性的值无法触发响应式。当你直接修改了对象属性的值，你会发现，只有数据改了，但是页面内容并没有改变</li>
<li>变异数组方法即保持数组方法原有功能不变的前提下对其进行功能拓展</li>
</ul>
<table>
<thead>
<tr>
<th><code>push()</code></th>
<th>往数组最后面添加一个元素，成功返回当前数组的长度</th>
</tr>
</thead>
<tbody><tr>
<td><code>pop()</code></td>
<td>删除数组的最后一个元素，成功返回删除元素的值</td>
</tr>
<tr>
<td><code>shift()</code></td>
<td>删除数组的第一个元素，成功返回删除元素的值</td>
</tr>
<tr>
<td><code>unshift()</code></td>
<td>往数组最前面添加一个元素，成功返回当前数组的长度</td>
</tr>
<tr>
<td><code>splice()</code></td>
<td>有三个参数，第一个是想要删除的元素的下标（必选），第二个是想要删除的个数（必选），第三个是删除 后想要在原位置替换的值</td>
</tr>
<tr>
<td><code>sort()</code></td>
<td>sort()  使数组按照字符编码默认从小到大排序,成功返回排序后的数组</td>
</tr>
<tr>
<td><code>reverse()</code></td>
<td>reverse()  将数组倒序，成功返回倒序后的数组</td>
</tr>
</tbody></table>
<h3 id="替换数组"><a href="#替换数组" class="headerlink" title="替换数组"></a>替换数组</h3><ul>
<li>不会改变原始数组，但总是返回一个新数组</li>
</ul>
<table>
<thead>
<tr>
<th>filter</th>
<th>filter() 方法创建一个新的数组，新数组中的元素是通过检查指定数组中符合条件的所有元素。</th>
</tr>
</thead>
<tbody><tr>
<td>concat</td>
<td>concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组</td>
</tr>
<tr>
<td>slice</td>
<td>slice() 方法可从已有的数组中返回选定的元素。该方法并不会修改数组，而是返回一个子数组</td>
</tr>
</tbody></table>
<h3 id="动态数组响应式数据"><a href="#动态数组响应式数据" class="headerlink" title="动态数组响应式数据"></a>动态数组响应式数据</h3><pre><code>Vue.set(vm.items, indexOfItem, newValue)
vm.$set(vm.items, indexOfItem, newValue)
参数一表示要处理的数组名称
参数二表示要处理的数组的索引
参数三表示要处理的数组的值</code></pre><ul>
<li>Vue.set(a,b,c)    让 触发视图重新更新一遍，数据动态起来</li>
<li>a是要更改的数据 、   b是数据的第几项、   c是更改后的数据</li>
</ul>
<h3 id="图书列表案例"><a href="#图书列表案例" class="headerlink" title="图书列表案例"></a>图书列表案例</h3><ul>
<li>静态列表效果</li>
<li>基于数据实现模板效果</li>
<li>处理每行的操作按钮</li>
</ul>
<h4 id="提供的静态数据"><a href="#提供的静态数据" class="headerlink" title="提供的静态数据"></a>提供的静态数据</h4><ul>
<li>数据存放在vue 中 data 属性中</li>
</ul>
<pre><code class="js"> var vm = new Vue({
      el: &#39;#app&#39;,
      data: {
        books: [{
          id: 1,
          name: &#39;三国演义&#39;,
          date: &#39;&#39;
        },{
          id: 2,
          name: &#39;水浒传&#39;,
          date: &#39;&#39;
        },{
          id: 3,
          name: &#39;红楼梦&#39;,
          date: &#39;&#39;
        },{
          id: 4,
          name: &#39;西游记&#39;,
          date: &#39;&#39;
        }]
      }
    }); var vm = new Vue({
      el: &#39;#app&#39;,
      data: {
        books: [{
          id: 1,
          name: &#39;三国演义&#39;,
          date: &#39;&#39;
        },{
          id: 2,
          name: &#39;水浒传&#39;,
          date: &#39;&#39;
        },{
          id: 3,
          name: &#39;红楼梦&#39;,
          date: &#39;&#39;
        },{
          id: 4,
          name: &#39;西游记&#39;,
          date: &#39;&#39;
        }]
      }
    });</code></pre>
<h4 id="把提供好的数据渲染到页面上"><a href="#把提供好的数据渲染到页面上" class="headerlink" title="把提供好的数据渲染到页面上"></a>把提供好的数据渲染到页面上</h4><ul>
<li>利用 v-for循环 遍历 books 将每一项数据渲染到对应的数据中</li>
</ul>
<pre><code class="html"> &lt;tbody&gt;
    &lt;tr :key=&#39;item.id&#39; v-for=&#39;item in books&#39;&gt;
       &lt;!-- 对应的id 渲染到页面上 --&gt;
       &lt;td&gt;{{item.id}}&lt;/td&gt;
        &lt;!-- 对应的name 渲染到页面上 --&gt;
       &lt;td&gt;{{item.name}}&lt;/td&gt;
       &lt;td&gt;{{item.date}}&lt;/td&gt;
       &lt;td&gt;
         &lt;!-- 阻止 a 标签的默认跳转 --&gt;
         &lt;a href=&quot;&quot; @click.prevent&gt;修改&lt;/a&gt;
         &lt;span&gt;|&lt;/span&gt;
             &lt;a href=&quot;&quot; @click.prevent&gt;删除&lt;/a&gt;
       &lt;/td&gt;
     &lt;/tr&gt;
&lt;/tbody&gt;</code></pre>
<h4 id="添加图书"><a href="#添加图书" class="headerlink" title="添加图书"></a>添加图书</h4><ul>
<li>通过双向绑定获取到输入框中的输入内容 </li>
<li>给按钮添加点击事件 </li>
<li>把输入框中的数据存储到 data 中的 books  里面</li>
</ul>
<pre><code class="html">&lt;div&gt;
  &lt;h1&gt;图书管理&lt;/h1&gt;
  &lt;div class=&quot;book&quot;&gt;
       &lt;div&gt;
         &lt;label for=&quot;id&quot;&gt;
           编号：
         &lt;/label&gt;
          &lt;!-- 3.1、通过双向绑定获取到输入框中的输入的 id  --&gt;
         &lt;input type=&quot;text&quot; id=&quot;id&quot; v-model=&#39;id&#39;&gt;
         &lt;label for=&quot;name&quot;&gt;
           名称：
         &lt;/label&gt;
           &lt;!-- 3.2、通过双向绑定获取到输入框中的输入的 name  --&gt;
         &lt;input type=&quot;text&quot; id=&quot;name&quot; v-model=&#39;name&#39;&gt;
            &lt;!-- 3.3、给按钮添加点击事件  --&gt;
         &lt;button @click=&#39;handle&#39;&gt;提交&lt;/button&gt;
       &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
  &lt;script type=&quot;text/javascript&quot;&gt;
    /*
      图书管理-添加图书
    */
    var vm = new Vue({
      el: &#39;#app&#39;,
      data: {
        id: &#39;&#39;,
        name: &#39;&#39;,
        books: [{
          id: 1,
          name: &#39;三国演义&#39;,
          date: &#39;&#39;
        },{
          id: 2,
          name: &#39;水浒传&#39;,
          date: &#39;&#39;
        },{
          id: 3,
          name: &#39;红楼梦&#39;,
          date: &#39;&#39;
        },{
          id: 4,
          name: &#39;西游记&#39;,
          date: &#39;&#39;
        }]
      },
      methods: {
        handle: function(){
          // 3.4 定义一个新的对象book 存储 获取到输入框中 书 的id和名字 
          var book = {};
          book.id = this.id;
          book.name = this.name;
          book.date = &#39;&#39;;
         // 3.5 把book  通过数组的变异方法 push 放到    books 里面
          this.books.push(book);
          //3.6 清空输入框
          this.id = &#39;&#39;;
          this.name = &#39;&#39;;
        }
      }
    });
  &lt;/script&gt;</code></pre>
<h4 id="修改图书-上"><a href="#修改图书-上" class="headerlink" title="修改图书-上"></a>修改图书-上</h4><ul>
<li>点击修改按钮的时候 获取到要修改的书籍名单<ul>
<li>给修改按钮添加点击事件，  需要把当前的图书的id 传递过去 这样才知道需要修改的是哪一本书籍</li>
</ul>
</li>
<li>把需要修改的书籍名单填充到表单里面<ul>
<li>根据传递过来的id 查出books 中 对应书籍的详细信息</li>
<li>把获取到的信息填充到表单</li>
</ul>
</li>
</ul>
<pre><code class="html"> &lt;div id=&quot;app&quot;&gt;
    &lt;div class=&quot;grid&quot;&gt;
      &lt;div&gt;
        &lt;h1&gt;图书管理&lt;/h1&gt;
        &lt;div class=&quot;book&quot;&gt;
          &lt;div&gt;
            &lt;label for=&quot;id&quot;&gt;
              编号：
            &lt;/label&gt;
            &lt;input type=&quot;text&quot; id=&quot;id&quot; v-model=&#39;id&#39; :disabled=&quot;flag&quot;&gt;
            &lt;label for=&quot;name&quot;&gt;
              名称：
            &lt;/label&gt;
            &lt;input type=&quot;text&quot; id=&quot;name&quot; v-model=&#39;name&#39;&gt;
            &lt;button @click=&#39;handle&#39;&gt;提交&lt;/button&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;table&gt;
        &lt;thead&gt;
          &lt;tr&gt;
            &lt;th&gt;编号&lt;/th&gt;
            &lt;th&gt;名称&lt;/th&gt;
            &lt;th&gt;时间&lt;/th&gt;
            &lt;th&gt;操作&lt;/th&gt;
          &lt;/tr&gt;
        &lt;/thead&gt;
        &lt;tbody&gt;
          &lt;tr :key=&#39;item.id&#39; v-for=&#39;item in books&#39;&gt;
            &lt;td&gt;{{item.id}}&lt;/td&gt;
            &lt;td&gt;{{item.name}}&lt;/td&gt;
            &lt;td&gt;{{item.date}}&lt;/td&gt;
            &lt;td&gt;
              &lt;!--- 
                4.1  给修改按钮添加点击事件，  需要把当前的图书的id 传递过去 
                这样才知道需要修改的是哪一本书籍
                  ---&gt;  
              &lt;a href=&quot;&quot; @click.prevent=&#39;toEdit(item.id)&#39;&gt;修改&lt;/a&gt;
              &lt;span&gt;|&lt;/span&gt;
              &lt;a href=&quot;&quot; @click.prevent&gt;删除&lt;/a&gt;
            &lt;/td&gt;
          &lt;/tr&gt;
        &lt;/tbody&gt;
      &lt;/table&gt;
    &lt;/div&gt;
  &lt;/div&gt;
 &lt;script type=&quot;text/javascript&quot;&gt;
    /*
      图书管理-添加图书
    */
    var vm = new Vue({
      el: &#39;#app&#39;,
      data: {
        flag: false,
        id: &#39;&#39;,
        name: &#39;&#39;,
        books: [{
          id: 1,
          name: &#39;三国演义&#39;,
          date: &#39;&#39;
        },{
          id: 2,
          name: &#39;水浒传&#39;,
          date: &#39;&#39;
        },{
          id: 3,
          name: &#39;红楼梦&#39;,
          date: &#39;&#39;
        },{
          id: 4,
          name: &#39;西游记&#39;,
          date: &#39;&#39;
        }]
      },
      methods: {
        handle: function(){
          // 3.4 定义一个新的对象book 存储 获取到输入框中 书 的id和名字 
          var book = {};
          book.id = this.id;
          book.name = this.name;
          book.date = &#39;&#39;;
         // 3.5 把book  通过数组的变异方法 push 放到    books 里面
          this.books.push(book);
          //3.6 清空输入框
          this.id = &#39;&#39;;
          this.name = &#39;&#39;;
        },
        toEdit: function(id){
          console.log(id)
          //4.2  根据传递过来的id 查出books 中 对应书籍的详细信息
          var book = this.books.filter(function(item){
            return item.id == id;
          });
          console.log(book)
          //4.3 把获取到的信息填充到表单
          // this.id   和  this.name 通过双向绑定 绑定到了表单中  一旦数据改变视图自动更新
          this.id = book[0].id;
          this.name = book[0].name;
        }
      }
    });
  &lt;/script&gt;</code></pre>
<h4 id="修改图书-下"><a href="#修改图书-下" class="headerlink" title="修改图书-下"></a>修改图书-下</h4><ul>
<li>定义一个标识符， 主要是控制 编辑状态下当前编辑书籍的id 不能被修改 即 处于编辑状态下 当前控制书籍编号的输入框禁用  </li>
<li>通过属性绑定给书籍编号的 绑定 disabled 的属性  flag 为 true 即为禁用</li>
<li>flag 默认值为false   处于编辑状态 要把 flag 改为true 即当前表单为禁用 </li>
<li>复用添加方法   用户点击提交的时候依然执行 handle 中的逻辑如果 flag为true 即 表单处于不可输入状态 此时执行的用户编辑数据数据</li>
</ul>
<pre><code class="html">&lt;div id=&quot;app&quot;&gt;
    &lt;div class=&quot;grid&quot;&gt;
      &lt;div&gt;
        &lt;h1&gt;图书管理&lt;/h1&gt;
        &lt;div class=&quot;book&quot;&gt;
          &lt;div&gt;
            &lt;label for=&quot;id&quot;&gt;
              编号：
            &lt;/label&gt;
              &lt;!-- 5.2 通过属性绑定 绑定 disabled 的属性  flag 为 true 即为禁用      --&gt;
            &lt;input type=&quot;text&quot; id=&quot;id&quot; v-model=&#39;id&#39; :disabled=&quot;flag&quot;&gt;
            &lt;label for=&quot;name&quot;&gt;
              名称：
            &lt;/label&gt;
            &lt;input type=&quot;text&quot; id=&quot;name&quot; v-model=&#39;name&#39;&gt;
            &lt;button @click=&#39;handle&#39;&gt;提交&lt;/button&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;table&gt;
        &lt;thead&gt;
          &lt;tr&gt;
            &lt;th&gt;编号&lt;/th&gt;
            &lt;th&gt;名称&lt;/th&gt;
            &lt;th&gt;时间&lt;/th&gt;
            &lt;th&gt;操作&lt;/th&gt;
          &lt;/tr&gt;
        &lt;/thead&gt;
        &lt;tbody&gt;
          &lt;tr :key=&#39;item.id&#39; v-for=&#39;item in books&#39;&gt;
            &lt;td&gt;{{item.id}}&lt;/td&gt;
            &lt;td&gt;{{item.name}}&lt;/td&gt;
            &lt;td&gt;{{item.date}}&lt;/td&gt;
            &lt;td&gt;
              &lt;a href=&quot;&quot; @click.prevent=&#39;toEdit(item.id)&#39;&gt;修改&lt;/a&gt;
              &lt;span&gt;|&lt;/span&gt;
              &lt;a href=&quot;&quot; @click.prevent&gt;删除&lt;/a&gt;
            &lt;/td&gt;
          &lt;/tr&gt;
        &lt;/tbody&gt;
      &lt;/table&gt;
    &lt;/div&gt;
  &lt;/div&gt;   
&lt;script type=&quot;text/javascript&quot;&gt;
        /*图书管理-添加图书*/
        var vm = new Vue({
            el: &#39;#app&#39;,
            data: {
                // 5.1  定义一个标识符， 主要是控制 编辑状态下当前编辑书籍的id 不能被修改 
                // 即 处于编辑状态下 当前控制书籍编号的输入框禁用 
                flag: false,
                id: &#39;&#39;,
                name: &#39;&#39;,

            },
            methods: {
                handle: function() {
                   /*
                     5.4  复用添加方法   用户点击提交的时候依然执行 handle 中的逻辑
                          如果 flag为true 即 表单处于不可输入状态 此时执行的用户编辑数据数据    
                   */ 
                    if (this.flag) {
                        // 编辑图书
                        // 5.5  根据当前的ID去更新数组中对应的数据  
                        this.books.some((item) =&gt; {
                            if (item.id == this.id) {
                                // 箭头函数中 this 指向父级作用域的this 
                                item.name = this.name;
                                // 完成更新操作之后，需要终止循环
                                return true;
                            }
                        });
                        // 5.6 编辑完数据后表单要处以可以输入的状态
                        this.flag = false;
                    //  5.7  如果 flag为false  表单处于输入状态 此时执行的用户添加数据    
                    } else { 
                        var book = {};
                        book.id = this.id;
                        book.name = this.name;
                        book.date = &#39;&#39;;
                        this.books.push(book);
                        // 清空表单
                        this.id = &#39;&#39;;
                        this.name = &#39;&#39;;
                    }
                    // 清空表单
                    this.id = &#39;&#39;;
                    this.name = &#39;&#39;;
                },
                toEdit: function(id) {
                     /*
                     5.3  flag 默认值为false   处于编辑状态 要把 flag 改为true 即当前表单为禁                      用 
                     */ 
                    this.flag = true;
                    console.log(id)
                    var book = this.books.filter(function(item) {
                        return item.id == id;
                    });
                    console.log(book)
                    this.id = book[0].id;
                    this.name = book[0].name;
                }
            }
        });
    &lt;/script&gt;</code></pre>
<h4 id="删除图书"><a href="#删除图书" class="headerlink" title="删除图书"></a>删除图书</h4><ul>
<li>给删除按钮添加事件 把当前需要删除的书籍id 传递过来</li>
<li>根据id从数组中查找元素的索引</li>
<li>根据索引删除数组元素</li>
</ul>
<pre><code class="html">  &lt;tbody&gt;
          &lt;tr :key=&#39;item.id&#39; v-for=&#39;item in books&#39;&gt;
            &lt;td&gt;{{item.id}}&lt;/td&gt;
            &lt;td&gt;{{item.name}}&lt;/td&gt;
            &lt;td&gt;{{item.date}}&lt;/td&gt;
            &lt;td&gt;
              &lt;a href=&quot;&quot; @click.prevent=&#39;toEdit(item.id)&#39;&gt;修改&lt;/a&gt;
              &lt;span&gt;|&lt;/span&gt;
               &lt;!--  6.1 给删除按钮添加事件 把当前需要删除的书籍id 传递过来  --&gt; 
              &lt;a href=&quot;&quot; @click.prevent=&#39;deleteBook(item.id)&#39;&gt;删除&lt;/a&gt;
            &lt;/td&gt;
          &lt;/tr&gt;
&lt;/tbody&gt;
  &lt;script type=&quot;text/javascript&quot;&gt;
    /*
      图书管理-添加图书
    */
    var vm = new Vue({
      methods: {
        deleteBook: function(id){
          // 删除图书
          #// 6.2 根据id从数组中查找元素的索引
          // var index = this.books.findIndex(function(item){
          //   return item.id == id;
          // });
          #// 6.3 根据索引删除数组元素
          // this.books.splice(index, 1);
          // -------------------------
         #// 方法二：通过filter方法进行删除

          # 6.4  根据filter 方法 过滤出来id 不是要删除书籍的id 
          # 因为 filter 是替换数组不会修改原始数据 所以需要 把 不是要删除书籍的id  赋值给 books 
          this.books = this.books.filter(function(item){
            return item.id != id;
          });
        }
      }
    });
  &lt;/script&gt;</code></pre>
<h3 id="常用特性应用场景"><a href="#常用特性应用场景" class="headerlink" title="常用特性应用场景"></a>常用特性应用场景</h3><h4 id="过滤器-1"><a href="#过滤器-1" class="headerlink" title="过滤器"></a>过滤器</h4><ul>
<li>Vue.filter  定义一个全局过滤器</li>
</ul>
<pre><code class="html"> &lt;tr :key=&#39;item.id&#39; v-for=&#39;item in books&#39;&gt;
            &lt;td&gt;{{item.id}}&lt;/td&gt;
            &lt;td&gt;{{item.name}}&lt;/td&gt;
             &lt;!-- 1.3  调用过滤器 --&gt;
            &lt;td&gt;{{item.date | format('yyyy-MM-dd hh:mm:ss')}}&lt;/td&gt;
            &lt;td&gt;
              &lt;a href=&quot;&quot; @click.prevent=&#39;toEdit(item.id)&#39;&gt;修改&lt;/a&gt;
              &lt;span&gt;|&lt;/span&gt;
              &lt;a href=&quot;&quot; @click.prevent=&#39;deleteBook(item.id)&#39;&gt;删除&lt;/a&gt;
            &lt;/td&gt;
&lt;/tr&gt;

&lt;script&gt;
        #1.1  Vue.filter  定义一个全局过滤器
        Vue.filter(&#39;format&#39;, function(value, arg) {
              function dateFormat(date, format) {
                if (typeof date === &quot;string&quot;) {
                  var mts = date.match(/(\/Date\((\d+)\)\/)/);
                  if (mts &amp;&amp; mts.length &gt;= 3) {
                    date = parseInt(mts[2]);
                  }
                }
                date = new Date(date);
                if (!date || date.toUTCString() == &quot;Invalid Date&quot;) {
                  return &quot;&quot;;
                }
                var map = {
                  &quot;M&quot;: date.getMonth() + 1, //月份 
                  &quot;d&quot;: date.getDate(), //日 
                  &quot;h&quot;: date.getHours(), //小时 
                  &quot;m&quot;: date.getMinutes(), //分 
                  &quot;s&quot;: date.getSeconds(), //秒 
                  &quot;q&quot;: Math.floor((date.getMonth() + 3) / 3), //季度 
                  &quot;S&quot;: date.getMilliseconds() //毫秒 
                };
                format = format.replace(/([yMdhmsqS])+/g, function(all, t) {
                  var v = map[t];
                  if (v !== undefined) {
                    if (all.length &gt; 1) {
                      v = &#39;0&#39; + v;
                      v = v.substr(v.length - 2);
                    }
                    return v;
                  } else if (t === &#39;y&#39;) {
                    return (date.getFullYear() + &#39;&#39;).substr(4 - all.length);
                  }
                  return all;
                });
                return format;
              }
              return dateFormat(value, arg);
            })
#1.2  提供的数据 包含一个时间戳   为毫秒数
   [{
          id: 1,
          name: &#39;三国演义&#39;,
          date: 2525609975000
        },{
          id: 2,
          name: &#39;水浒传&#39;,
          date: 2525609975000
        },{
          id: 3,
          name: &#39;红楼梦&#39;,
          date: 2525609975000
        },{
          id: 4,
          name: &#39;西游记&#39;,
          date: 2525609975000
        }];
&lt;/script&gt;</code></pre>
<h4 id="自定义指令-1"><a href="#自定义指令-1" class="headerlink" title="自定义指令"></a>自定义指令</h4><ul>
<li>让表单自动获取焦点</li>
<li>通过Vue.directive 自定义指定</li>
</ul>
<pre><code class="html">&lt;!-- 2.2  通过v-自定义属性名 调用自定义指令 --&gt;
&lt;input type=&quot;text&quot; id=&quot;id&quot; v-model=&#39;id&#39; :disabled=&quot;flag&quot; v-focus&gt;

&lt;script&gt;
    # 2.1   通过Vue.directive 自定义指定
    Vue.directive(&#39;focus&#39;, {
      inserted: function (el) {
        el.focus();
      }
    });

&lt;/script&gt;</code></pre>
<h4 id="计算属性"><a href="#计算属性" class="headerlink" title="计算属性"></a>计算属性</h4><ul>
<li>通过计算属性计算图书的总数<ul>
<li>图书的总数就是计算数组的长度 </li>
</ul>
</li>
</ul>
<pre><code class="html"> &lt;div class=&quot;total&quot;&gt;
        &lt;span&gt;图书总数：&lt;/span&gt;
         &lt;!-- 3.2 在页面上 展示出来 --&gt;
        &lt;span&gt;{{total}}&lt;/span&gt;
&lt;/div&gt;

  &lt;script type=&quot;text/javascript&quot;&gt;
    /*
      计算属性与方法的区别:计算属性是基于依赖进行缓存的，而方法不缓存
    */
    var vm = new Vue({
      data: {
        flag: false,
        submitFlag: false,
        id: &#39;&#39;,
        name: &#39;&#39;,
        books: []
      },
      computed: {
        total: function(){
          // 3.1  计算图书的总数
          return this.books.length;
        }
      },
    });
  &lt;/script&gt;
</code></pre>
<h4 id="生命周期-1"><a href="#生命周期-1" class="headerlink" title="生命周期"></a>生命周期</h4><h2 id="day03"><a href="#day03" class="headerlink" title="day03"></a>day03</h2><h3 id="组件"><a href="#组件" class="headerlink" title="组件"></a>组件</h3><ul>
<li>组件 (Component) 是 Vue.js 最强大的功能之一</li>
<li>组件可以扩展 HTML 元素，封装可重用的代</li>
</ul>
<h3 id="组件注册"><a href="#组件注册" class="headerlink" title="组件注册"></a>组件注册</h3><h4 id="全局注册"><a href="#全局注册" class="headerlink" title="全局注册"></a>全局注册</h4><ul>
<li>Vue.component(‘组件名称’, { })     第1个参数是标签名称，第2个参数是一个选项对象</li>
<li><strong>全局组件</strong>注册后，任何<strong>vue实例</strong>都可以用</li>
</ul>
<h5 id="组件基础用"><a href="#组件基础用" class="headerlink" title="组件基础用"></a>组件基础用</h5><pre><code>// 注册一个名为 button-counter 的新组件
Vue.component(&#39;button-counter&#39;, {
    data: function () {
        return {
            count: 0
        }
    },
    template: &#39;&lt;button v-on:click=&quot;count++&quot;&gt;点击了{{ count }}次.&lt;/button&gt;&#39;
})
//使用该组件
&lt;div id=&quot;app&quot;&gt;
    &lt;button-counter&gt;&lt;/button-counter&gt;
&lt;/div&gt;</code></pre><h5 id="组件注意事项"><a href="#组件注意事项" class="headerlink" title="组件注意事项"></a>组件注意事项</h5><ul>
<li>组件参数的data值必须是函数，同时这个函数要求返回一个对象 </li>
<li>组件模板内容必须是单个根元素</li>
<li>组件模板的内容可以是模板字符串 ``（ES6语法） </li>
</ul>
<pre><code>组件命名方式
短横线方式
Vue.component(&#39;my-component&#39;, { /* ... */ })
驼峰方式(不建议)
Vue.component(&#39;MyComponent&#39;, { /* ... */ })</code></pre><pre><code class="html">  &lt;div id=&quot;app&quot;&gt;
     &lt;!-- 
        4、  组件可以重复使用多次 
          因为data中返回的是一个对象所以每个组件中的数据是私有的
          即每个实例可以维护一份被返回对象的独立的拷贝   
    --&gt; 
    &lt;button-counter&gt;&lt;/button-counter&gt;
    &lt;button-counter&gt;&lt;/button-counter&gt;
    &lt;button-counter&gt;&lt;/button-counter&gt;
      &lt;!-- 8、必须使用短横线的方式使用组件 --&gt;
     &lt;hello-world&gt;&lt;/hello-world&gt;
  &lt;/div&gt;

&lt;script type=&quot;text/javascript&quot;&gt;
    //5  如果使用驼峰式命名组件，那么在使用组件的时候，只能在字符串模板中用驼峰的方式使用组件，
    // 7、但是在普通的标签模板中，必须使用短横线的方式使用组件
     Vue.component(&#39;HelloWorld&#39;, {
      data: function(){
        return {
          msg: &#39;HelloWorld&#39;
        }
      },
      template: &#39;&lt;div&gt;{{msg}}&lt;/div&gt;&#39;
    });



    Vue.component(&#39;button-counter&#39;, {
      // 1、组件参数的data值必须是函数 
      // 同时这个函数要求返回一个对象  
      data: function(){
        return {
          count: 0
        }
      },
      //  2、组件模板必须是单个根元素
      //  3、组件模板的内容可以是模板字符串  
      template: `
        &lt;div&gt;
          &lt;button @click=&quot;handle&quot;&gt;点击了{{count}}次&lt;/button&gt;
          &lt;button&gt;测试123&lt;/button&gt;
            #  6 在字符串模板中可以使用驼峰的方式使用组件    
           &lt;HelloWorld&gt;&lt;/HelloWorld&gt;
        &lt;/div&gt;
      `,
      methods: {
        handle: function(){
          this.count += 2;
        }
      }
    })
    var vm = new Vue({
      el: &#39;#app&#39;,
      data: {

      }
    });
  &lt;/script&gt;</code></pre>
<h4 id="局部注册"><a href="#局部注册" class="headerlink" title="局部注册"></a>局部注册</h4><ul>
<li>只能在当前注册它的vue实例中使用</li>
</ul>
<pre><code class="html">  &lt;div id=&quot;app&quot;&gt;
      &lt;my-component&gt;&lt;/my-component&gt;
  &lt;/div&gt;


&lt;script&gt;

    // 定义组件的模板
    var Child = {
      template: &#39;&lt;div&gt;A custom component!&lt;/div&gt;&#39;
    }
    new Vue({
      //局部注册组件  
      components: {
        // &lt;my-component&gt; 将只在父模板可用  一定要在实例上注册了才能在html文件中使用
        &#39;my-component&#39;: Child
      }
    })
 &lt;/script&gt;</code></pre>
<h3 id="Vue-调试工具"><a href="#Vue-调试工具" class="headerlink" title="Vue 调试工具"></a>Vue 调试工具</h3><p><a href="https://github.com/vuejs/vue-devtools" target="_blank" rel="noopener">https://github.com/vuejs/vue-devtools</a></p>
<h3 id="Vue组件之间传值"><a href="#Vue组件之间传值" class="headerlink" title="Vue组件之间传值"></a>Vue组件之间传值</h3><h4 id="父组件向子组件传值"><a href="#父组件向子组件传值" class="headerlink" title="父组件向子组件传值"></a>父组件向子组件传值</h4><ul>
<li>父组件发送的形式是以属性的形式绑定值到子组件身上。</li>
<li>然后子组件用属性props接收</li>
<li>在props中使用驼峰形式，模板中需要使用短横线的形式， 字符串形式的模板中没有这个限制</li>
<li>props属性值类型：字符串 String 数值 Number 布尔值 Boolean 数组 Array 对象 Object </li>
</ul>
<pre><code class="html">  &lt;div id=&quot;app&quot;&gt;
    &lt;div&gt;{{pmsg}}&lt;/div&gt;
     &lt;!--1、menu-item  在 APP中嵌套着 故 menu-item   为  子组件      --&gt;
     &lt;!-- 给子组件传入一个静态的值 --&gt;
    &lt;menu-item title=&#39;来自父组件的值&#39;&gt;&lt;/menu-item&gt;
    &lt;!-- 2、 需要动态的数据的时候 需要属性绑定的形式设置 此时 ptitle  来自父组件data 中的数据 . 
          传的值可以是数字、对象、数组等等
    --&gt;
    &lt;menu-item :title=&#39;ptitle&#39; content=&#39;hello&#39;&gt;&lt;/menu-item&gt;
  &lt;/div&gt;

  &lt;script type=&quot;text/javascript&quot;&gt;
    Vue.component(&#39;menu-item&#39;, {
      // 3、 子组件用属性props接收父组件传递过来的数据  
      props: [&#39;title&#39;, &#39;content&#39;],
      data: function() {
        return {
          msg: &#39;子组件本身的数据&#39;
        }
      },
      template: &#39;&lt;div&gt;{{msg + "----" + title + "-----" + content}}&lt;/div&gt;&#39;
    });
    var vm = new Vue({
      el: &#39;#app&#39;,
      data: {
        pmsg: &#39;父组件中内容&#39;,
        ptitle: &#39;动态绑定属性&#39;
      }
    });
  &lt;/script&gt;</code></pre>
<h4 id="子组件向父组件传值"><a href="#子组件向父组件传值" class="headerlink" title="子组件向父组件传值"></a>子组件向父组件传值</h4><ul>
<li>子组件用<code>$emit()</code>触发事件</li>
<li><code>$emit()</code>  第一个参数为 自定义的事件名称     第二个参数为需要传递的数据</li>
<li>父组件用v-on 监听子组件的事件 </li>
</ul>
<pre><code class="html">
&lt;div id=&quot;app&quot;&gt;
    &lt;div :style=&#39;{fontSize: fontSize + &quot;px&quot;}&#39;&gt;{{pmsg}}&lt;/div&gt;
    &lt;!--父组件用v-on 监听子组件的事件
这里 enlarge-text  是从 $emit 中的第一个参数对应   handle 为对应的事件处理函数--&gt;    
    &lt;menu-item :parr=&#39;parr&#39; @enlarge-text=&#39;handle($event)&#39;&gt;&lt;/menu-item&gt;
&lt;/div&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;js/vue.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
    //子组件向父组件传值-携带参数
    Vue.component(&#39;menu-item&#39;, {
        props: [&#39;parr&#39;],
        template: `
&lt;div&gt;
    &lt;ul&gt;
        &lt;li :key=&#39;index&#39; v-for=&#39;(item,index) in parr&#39;&gt;{{item}}&lt;/li&gt;
    &lt;/ul&gt;
###  1、子组件用$emit()触发事件
### 第一个参数为 自定义的事件名称   第二个参数为需要传递的数据  
    &lt;button @click=&#39;$emit(&quot;enlarge-text&quot;, 5)&#39;&gt;扩大父组件中字体大小&lt;/button&gt;
    &lt;button @click=&#39;$emit(&quot;enlarge-text&quot;, 10)&#39;&gt;扩大父组件中字体大小&lt;/button&gt;
&lt;/div&gt;
`
    });
    var vm = new Vue({
        el: &#39;#app&#39;,
        data: {
            pmsg: &#39;父组件中内容&#39;,
            parr: [&#39;apple&#39;,&#39;orange&#39;,&#39;banana&#39;],
            fontSize: 10
        },
        methods: {
            handle: function(val){
                // 扩大字体大小
                this.fontSize += val;
            }
        }
    });
&lt;/script&gt;</code></pre>
<h4 id="兄弟之间的传递"><a href="#兄弟之间的传递" class="headerlink" title="兄弟之间的传递"></a>兄弟之间的传递</h4><ul>
<li><p>兄弟之间传递数据需要借助于事件中心，通过事件中心传递数据   </p>
<ul>
<li>提供事件中心    var hub = new Vue()</li>
</ul>
</li>
<li><p>传递数据方，通过一个事件触发hub.$emit(方法名，传递的数据)</p>
</li>
<li><p>接收数据方，通过<code>mounted(){}</code> 钩子中  触发<code>hub.$on()</code>方法名</p>
</li>
<li><p>销毁事件 通过<code>hub.$off()</code>方法名销毁之后无法进行传递数据</p>
<img src="http://helloxx.cn/4.png" srcset="/myblog/img/loading.gif" style="zoom:80%;" />

</li>
</ul>
<pre><code class="html"> &lt;div id=&quot;app&quot;&gt;
    &lt;div&gt;父组件&lt;/div&gt;
    &lt;div&gt;
      &lt;button @click=&#39;handle&#39;&gt;销毁事件&lt;/button&gt;
    &lt;/div&gt;
    &lt;test-tom&gt;&lt;/test-tom&gt;
    &lt;test-jerry&gt;&lt;/test-jerry&gt;
  &lt;/div&gt;
  &lt;script type=&quot;text/javascript&quot; src=&quot;js/vue.js&quot;&gt;&lt;/script&gt;
  &lt;script type=&quot;text/javascript&quot;&gt;
    /*
      兄弟组件之间数据传递
    */
    //1、 提供事件中心
    var hub = new Vue();

    Vue.component(&#39;test-tom&#39;, {
      data: function(){
        return {
          num: 0
        }
      },
      template: `
        &lt;div&gt;
          &lt;div&gt;TOM:{{num}}&lt;/div&gt;
          &lt;div&gt;
            &lt;button @click=&#39;handle&#39;&gt;点击&lt;/button&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      `,
      methods: {
        handle: function(){
          //2、传递数据方，通过一个事件触发hub.$emit(方法名，传递的数据)   触发兄弟组件的事件
          hub.$emit(&#39;jerry-event&#39;, 2);
        }
      },
      mounted: function() {
       // 3、接收数据方，通过mounted(){} 钩子中  触发hub.$on(方法名
        hub.$on(&#39;tom-event&#39;, (val) =&gt; {
          this.num += val;
        });
      }
    });
    Vue.component(&#39;test-jerry&#39;, {
      data: function(){
        return {
          num: 0
        }
      },
      template: `
        &lt;div&gt;
          &lt;div&gt;JERRY:{{num}}&lt;/div&gt;
          &lt;div&gt;
            &lt;button @click=&#39;handle&#39;&gt;点击&lt;/button&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      `,
      methods: {
        handle: function(){
          //2、传递数据方，通过一个事件触发hub.$emit(方法名，传递的数据)   触发兄弟组件的事件
          hub.$emit(&#39;tom-event&#39;, 1);
        }
      },
      mounted: function() {
        // 3、接收数据方，通过mounted(){} 钩子中  触发hub.$on()方法名
        hub.$on(&#39;jerry-event&#39;, (val) =&gt; {
          this.num += val;
        });
      }
    });
    var vm = new Vue({
      el: &#39;#app&#39;,
      data: {

      },
      methods: {
        handle: function(){
          //4、销毁事件 通过hub.$off()方法名销毁之后无法进行传递数据  
          hub.$off(&#39;tom-event&#39;);
          hub.$off(&#39;jerry-event&#39;);
        }
      }
    });
  &lt;/script&gt;
</code></pre>
<h3 id="Prop-验证"><a href="#Prop-验证" class="headerlink" title="Prop 验证"></a>Prop 验证</h3><pre><code class="js">Vue.component(&#39;child&#39;, {
    props:{
        content:{type: String,
                 required: false,
                 default: &#39;default valus&#39;}
    }
})</code></pre>
<h3 id="组件插槽"><a href="#组件插槽" class="headerlink" title="组件插槽"></a>组件插槽</h3><ul>
<li>组件 slot 的最大特性就是复用性，而用好插槽能大大提高组件的可复用能力</li>
</ul>
<pre><code class="html">&lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
        &lt;alert-box&gt;有bug发生&lt;/alert-box&gt; //error:有bug发生
        &lt;alert-box&gt;有一个警告&lt;/alert-box&gt;//error:有一个警告
        &lt;alert-box&gt;&lt;/alert-box&gt;//error:内容    //当不填写内容时，则显示slot里的内容
    &lt;/div&gt;
&lt;/body&gt;
&lt;script&gt;
    Vue.component(&#39;alert-box&#39;, {
        template: `
            &lt;div&gt;
                &lt;strong&gt;ERROR:&lt;/strong&gt;
                &lt;slot&gt;内容&lt;/slot&gt;
            &lt;/div&gt;
        `
    });
    var vm = new Vue({
        el: &#39;#app&#39;,
        data: {}
    })
&lt;/script&gt;</code></pre>
<h4 id="具名插槽"><a href="#具名插槽" class="headerlink" title="具名插槽"></a>具名插槽</h4><ul>
<li>具有名字的插槽 </li>
<li>使用<code>&lt;slot&gt;</code>中的 “name” 属性绑定元素，使其生成的html呈对应形式</li>
<li>也可以使用<code>&lt;template slot=&quot;header&quot;&gt;</code>的形式来使用，可以在页面标签量大时使用，template 标签不会渲染到页面中</li>
</ul>
<pre><code class="HTML">&lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
        &lt;base-layout&gt;
            &lt;p slot=&quot;header&quot;&gt;头部内容&lt;/p&gt;
            &lt;p slot=&quot;header&quot;&gt;头部内容&lt;/p&gt;
            &lt;p&gt;主要内容&lt;/p&gt;
            &lt;p&gt;主要内容&lt;/p&gt;
            &lt;p slot=&quot;footer&quot;&gt;尾部内容&lt;/p&gt;
            &lt;p slot=&quot;footer&quot;&gt;尾部内容&lt;/p&gt;
        &lt;/base-layout&gt;
    &lt;/div&gt;
&lt;/body&gt;
-------template用法--------
&lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
        &lt;base-layout&gt;
            &lt;template slot=&quot;header&quot;&gt;
                &lt;p&gt;头部内容&lt;/p&gt;
                &lt;p&gt;头部内容&lt;/p&gt;
            &lt;/template&gt;
            &lt;p&gt;主要内容&lt;/p&gt;
            &lt;p&gt;主要内容&lt;/p&gt;
            &lt;template slot=&quot;footer&quot;&gt;
                &lt;p&gt;尾部内容&lt;/p&gt;
                &lt;p&gt;尾部内容&lt;/p&gt;
            &lt;/template&gt;
        &lt;/base-layout&gt;
    &lt;/div&gt;
&lt;/body&gt;
&lt;script&gt;
    Vue.component(&#39;base-layout&#39;, {
        template: `
            &lt;div&gt;
                &lt;header&gt;
                    &lt;slot name=&quot;header&quot;&gt;&lt;/slot&gt;
                &lt;/header&gt;
                &lt;main&gt;
                    &lt;slot&gt;&lt;/slot&gt;
                &lt;/main&gt;
                &lt;footer&gt;
                    &lt;slot name=&quot;footer&quot;&gt;&lt;/slot&gt;
                &lt;/footer&gt;
            &lt;/div&gt;
        `
    });
    var vm = new Vue({
        el: &#39;#app&#39;,
        data: {}
    })
&lt;/script&gt;
——————————呈现出的html————————————
&lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
        &lt;div&gt;
            &lt;header&gt;
                &lt;p&gt;头部内容&lt;/p&gt;
                &lt;p&gt;头部内容&lt;/p&gt;
            &lt;/header&gt;
            &lt;main&gt;
                &lt;p&gt;主要内容&lt;/p&gt;
                &lt;p&gt;主要内容&lt;/p&gt;
            &lt;/main&gt;
            &lt;footer&gt;
                &lt;p&gt;尾部内容&lt;/p&gt;
                &lt;p&gt;尾部内容&lt;/p&gt;
            &lt;/footer&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/body&gt;</code></pre>
<h4 id="作用域插槽"><a href="#作用域插槽" class="headerlink" title="作用域插槽"></a>作用域插槽</h4><ul>
<li>父组件对子组件的内容进行加工处理</li>
<li>既可以复用子组件的slot，又可以使slot内容不一致</li>
</ul>
<pre><code class="html">  &lt;div id=&quot;app&quot;&gt;
    &lt;!-- 
        1、当我们希望li 的样式由外部使用组件的地方定义，因为可能有多种地方要使用该组件，
        但样式希望不一样 这个时候我们需要使用作用域插槽 

    --&gt;  
    &lt;fruit-list :list=&#39;list&#39;&gt;
       &lt;!-- 2、 父组件中使用了&lt;template&gt;元素,而且包含scope=&quot;slotProps&quot;,
            slotProps在这里只是临时变量   
        ---&gt;     
      &lt;template slot-scope=&#39;slotProps&#39;&gt;
        &lt;strong v-if=&#39;slotProps.info.id==3&#39; class=&quot;current&quot;&gt;
            {{slotProps.info.name}}                 
         &lt;/strong&gt;
        &lt;span v-else&gt;{{slotProps.info.name}}&lt;/span&gt;
      &lt;/template&gt;
    &lt;/fruit-list&gt;
  &lt;/div&gt;
  &lt;script type=&quot;text/javascript&quot; src=&quot;js/vue.js&quot;&gt;&lt;/script&gt;
  &lt;script type=&quot;text/javascript&quot;&gt;
    /*作用域插槽*/
    Vue.component(&#39;fruit-list&#39;, {
      props: [&#39;list&#39;],
      template: `
        &lt;div&gt;
          &lt;li :key=&#39;item.id&#39; v-for=&#39;item in list&#39;&gt;
            ###  3、 在子组件模板中,&lt;slot&gt;元素上有一个类似props传递数据给组件的写法msg=&quot;xxx&quot;,
            ###   插槽可以提供一个默认内容，如果如果父组件没有为这个插槽提供了内容，会显示默认的内容。
                    如果父组件为这个插槽提供了内容，则默认的内容会被替换掉
            &lt;slot :info=&#39;item&#39;&gt;{{item.name}}&lt;/slot&gt;
          &lt;/li&gt;
        &lt;/div&gt;
      `
    });
    var vm = new Vue({
      el: &#39;#app&#39;,
      data: {
        list: [{
          id: 1,
          name: &#39;apple&#39;
        },{
          id: 2,
          name: &#39;orange&#39;
        },{
          id: 3,
          name: &#39;banana&#39;
        }]
      }
    });
  &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<h3 id="购物车案例"><a href="#购物车案例" class="headerlink" title="购物车案例"></a>购物车案例</h3><h4 id="1-实现组件化布局"><a href="#1-实现组件化布局" class="headerlink" title="1.  实现组件化布局"></a>1.  实现组件化布局</h4><ul>
<li>把静态页面转换成组件化模式</li>
<li>把组件渲染到页面上</li>
</ul>
<pre><code class="html"> &lt;div id=&quot;app&quot;&gt;
    &lt;div class=&quot;container&quot;&gt;
      &lt;!-- 2、把组件渲染到页面上 --&gt; 
      &lt;my-cart&gt;&lt;/my-cart&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;script type=&quot;text/javascript&quot; src=&quot;js/vue.js&quot;&gt;&lt;/script&gt;
  &lt;script type=&quot;text/javascript&quot;&gt;
    # 1、 把静态页面转换成组件化模式
    # 1.1  标题组件 
    var CartTitle = {
      template: `
        &lt;div class=&quot;title&quot;&gt;我的商品&lt;/div&gt;
      `
    }
    # 1.2  商品列表组件 
    var CartList = {
      #  注意点 ：  组件模板必须是单个根元素  
      template: `
        &lt;div&gt;
          &lt;div class=&quot;item&quot;&gt;
            &lt;img src=&quot;img/a.jpg&quot;/&gt;
            &lt;div class=&quot;name&quot;&gt;&lt;/div&gt;
            &lt;div class=&quot;change&quot;&gt;
              &lt;a href=&quot;&quot;&gt;－&lt;/a&gt;
              &lt;input type=&quot;text&quot; class=&quot;num&quot; /&gt;
              &lt;a href=&quot;&quot;&gt;＋&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;del&quot;&gt;×&lt;/div&gt;
          &lt;/div&gt;
          &lt;div class=&quot;item&quot;&gt;
            &lt;img src=&quot;img/b.jpg&quot;/&gt;
            &lt;div class=&quot;name&quot;&gt;&lt;/div&gt;
            &lt;div class=&quot;change&quot;&gt;
              &lt;a href=&quot;&quot;&gt;－&lt;/a&gt;
              &lt;input type=&quot;text&quot; class=&quot;num&quot; /&gt;
              &lt;a href=&quot;&quot;&gt;＋&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;del&quot;&gt;×&lt;/div&gt;
          &lt;/div&gt;
          &lt;div class=&quot;item&quot;&gt;
            &lt;img src=&quot;img/c.jpg&quot;/&gt;
            &lt;div class=&quot;name&quot;&gt;&lt;/div&gt;
            &lt;div class=&quot;change&quot;&gt;
              &lt;a href=&quot;&quot;&gt;－&lt;/a&gt;
              &lt;input type=&quot;text&quot; class=&quot;num&quot; /&gt;
              &lt;a href=&quot;&quot;&gt;＋&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;del&quot;&gt;×&lt;/div&gt;
          &lt;/div&gt;
          &lt;div class=&quot;item&quot;&gt;
            &lt;img src=&quot;img/d.jpg&quot;/&gt;
            &lt;div class=&quot;name&quot;&gt;&lt;/div&gt;
            &lt;div class=&quot;change&quot;&gt;
              &lt;a href=&quot;&quot;&gt;－&lt;/a&gt;
              &lt;input type=&quot;text&quot; class=&quot;num&quot; /&gt;
              &lt;a href=&quot;&quot;&gt;＋&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;del&quot;&gt;×&lt;/div&gt;
          &lt;/div&gt;
          &lt;div class=&quot;item&quot;&gt;
            &lt;img src=&quot;img/e.jpg&quot;/&gt;
            &lt;div class=&quot;name&quot;&gt;&lt;/div&gt;
            &lt;div class=&quot;change&quot;&gt;
              &lt;a href=&quot;&quot;&gt;－&lt;/a&gt;
              &lt;input type=&quot;text&quot; class=&quot;num&quot; /&gt;
              &lt;a href=&quot;&quot;&gt;＋&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;del&quot;&gt;×&lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      `
    }
    # 1.3  商品结算组件 
    var CartTotal = {
      template: `
        &lt;div class=&quot;total&quot;&gt;
          &lt;span&gt;总价：123&lt;/span&gt;
          &lt;button&gt;结算&lt;/button&gt;
        &lt;/div&gt;
      `
    }
    ## 1.4  定义一个全局组件 my-cart
    Vue.component(&#39;my-cart&#39;,{
      ##  1.6 引入子组件  
      template: `
        &lt;div class=&#39;cart&#39;&gt;
          &lt;cart-title&gt;&lt;/cart-title&gt;
          &lt;cart-list&gt;&lt;/cart-list&gt;
          &lt;cart-total&gt;&lt;/cart-total&gt;
        &lt;/div&gt;
      `,
      # 1.5  注册子组件   
      components: {
        &#39;cart-title&#39;: CartTitle,
        &#39;cart-list&#39;: CartList,
        &#39;cart-total&#39;: CartTotal
      }
    });
    var vm = new Vue({
      el: &#39;#app&#39;,
      data: {

      }
    });

  &lt;/script&gt;


</code></pre>
<h4 id="2、实现-标题和结算功能组件"><a href="#2、实现-标题和结算功能组件" class="headerlink" title="2、实现 标题和结算功能组件"></a>2、实现 标题和结算功能组件</h4><ul>
<li>标题组件实现动态渲染<ul>
<li>从父组件把标题数据传递过来 即 父向子组件传值</li>
<li>把传递过来的数据渲染到页面上  </li>
</ul>
</li>
<li>结算功能组件<ul>
<li>从父组件把商品列表list 数据传递过来 即 父向子组件传值</li>
<li>把传递过来的数据计算最终价格渲染到页面上  </li>
</ul>
</li>
</ul>
<pre><code class="html"> &lt;div id=&quot;app&quot;&gt;
    &lt;div class=&quot;container&quot;&gt;
      &lt;my-cart&gt;&lt;/my-cart&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;script type=&quot;text/javascript&quot; src=&quot;js/vue.js&quot;&gt;&lt;/script&gt;
  &lt;script type=&quot;text/javascript&quot;&gt;
     # 2.2  标题组件     子组件通过props形式接收父组件传递过来的uname数据
    var CartTitle = {
      props: [&#39;uname&#39;],
      template: `
        &lt;div class=&quot;title&quot;&gt;{{uname}}的商品&lt;/div&gt;
      `
    }
    # 2.3  商品结算组件  子组件通过props形式接收父组件传递过来的list数据   
    var CartTotal = {
      props: [&#39;list&#39;],
      template: `
        &lt;div class=&quot;total&quot;&gt;
          &lt;span&gt;总价：{{total}}&lt;/span&gt;
          &lt;button&gt;结算&lt;/button&gt;
        &lt;/div&gt;
      `,
      computed: {
        # 2.4    计算商品的总价  并渲染到页面上 
        total: function() {
          var t = 0;
          this.list.forEach(item =&gt; {
            t += item.price * item.num;
          });
          return t;
        }
      }
    }
    Vue.component(&#39;my-cart&#39;,{
      data: function() {
        return {
          uname: &#39;张三&#39;,
          list: [{
            id: 1,
            name: &#39;TCL彩电&#39;,
            price: 1000,
            num: 1,
            img: &#39;img/a.jpg&#39;
          },{
            id: 2,
            name: &#39;机顶盒&#39;,
            price: 1000,
            num: 1,
            img: &#39;img/b.jpg&#39;
          },{
            id: 3,
            name: &#39;海尔冰箱&#39;,
            price: 1000,
            num: 1,
            img: &#39;img/c.jpg&#39;
          },{
            id: 4,
            name: &#39;小米手机&#39;,
            price: 1000,
            num: 1,
            img: &#39;img/d.jpg&#39;
          },{
            id: 5,
            name: &#39;PPTV电视&#39;,
            price: 1000,
            num: 2,
            img: &#39;img/e.jpg&#39;
          }]
        }
      },
      #  2.1  父组件向子组件以属性传递的形式 传递数据
      #   向 标题组件传递 uname 属性   向 商品结算组件传递 list  属性  
      template: `
        &lt;div class=&#39;cart&#39;&gt;
          &lt;cart-title :uname=&#39;uname&#39;&gt;&lt;/cart-title&gt;
          &lt;cart-list&gt;&lt;/cart-list&gt;
          &lt;cart-total :list=&#39;list&#39;&gt;&lt;/cart-total&gt;
        &lt;/div&gt;
      `,
      components: {
        &#39;cart-title&#39;: CartTitle,
        &#39;cart-list&#39;: CartList,
        &#39;cart-total&#39;: CartTotal
      }
    });
    var vm = new Vue({
      el: &#39;#app&#39;,
      data: {

      }
    });

  &lt;/script&gt;
</code></pre>
<h4 id="3-实现列表组件删除功能"><a href="#3-实现列表组件删除功能" class="headerlink" title="3.  实现列表组件删除功能"></a>3.  实现列表组件删除功能</h4><ul>
<li>从父组件把商品列表list 数据传递过来 即 父向子组件传值</li>
<li>把传递过来的数据渲染到页面上    </li>
<li>点击删除按钮的时候删除对应的数据 <ul>
<li>给按钮添加点击事件把需要删除的id传递过来  <ul>
<li>子组件中不推荐操作父组件的数据有可能多个子组件使用父组件的数据  我们需要把数据传递给父组件让父组件操作数据 </li>
<li>父组件删除对应的数据</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code class="html"> &lt;div id=&quot;app&quot;&gt;
    &lt;div class=&quot;container&quot;&gt;
      &lt;my-cart&gt;&lt;/my-cart&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;script type=&quot;text/javascript&quot; src=&quot;js/vue.js&quot;&gt;&lt;/script&gt;
  &lt;script type=&quot;text/javascript&quot;&gt;

    var CartTitle = {
      props: [&#39;uname&#39;],
      template: `
        &lt;div class=&quot;title&quot;&gt;{{uname}}的商品&lt;/div&gt;
      `
    }
    #  3.2 把列表数据动态渲染到页面上  
    var CartList = {
      props: [&#39;list&#39;],
      template: `
        &lt;div&gt;
          &lt;div :key=&#39;item.id&#39; v-for=&#39;item in list&#39; class=&quot;item&quot;&gt;
            &lt;img :src=&quot;item.img&quot;/&gt;
            &lt;div class=&quot;name&quot;&gt;{{item.name}}&lt;/div&gt;
            &lt;div class=&quot;change&quot;&gt;
              &lt;a href=&quot;&quot;&gt;－&lt;/a&gt;
              &lt;input type=&quot;text&quot; class=&quot;num&quot; /&gt;
              &lt;a href=&quot;&quot;&gt;＋&lt;/a&gt;
            &lt;/div&gt;
            # 3.3  给按钮添加点击事件把需要删除的id传递过来
            &lt;div class=&quot;del&quot; @click=&#39;del(item.id)&#39;&gt;×&lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      `,
      methods: {
        del: function(id){
           # 3.4 子组件中不推荐操作父组件的数据有可能多个子组件使用父组件的数据 
          #       我们需要把数据传递给父组件 让父组件操作数据 
          this.$emit(&#39;cart-del&#39;, id);
        }
      }
    }
    var CartTotal = {
      props: [&#39;list&#39;],
      template: `
        &lt;div class=&quot;total&quot;&gt;
          &lt;span&gt;总价：{{total}}&lt;/span&gt;
          &lt;button&gt;结算&lt;/button&gt;
        &lt;/div&gt;
      `,
      computed: {
        total: function() {
          // 计算商品的总价
          var t = 0;
          this.list.forEach(item =&gt; {
            t += item.price * item.num;
          });
          return t;
        }
      }
    }
    Vue.component(&#39;my-cart&#39;,{
      data: function() {
        return {
          uname: &#39;张三&#39;,
          list: [{
            id: 1,
            name: &#39;TCL彩电&#39;,
            price: 1000,
            num: 1,
            img: &#39;img/a.jpg&#39;
          },{
            id: 2,
            name: &#39;机顶盒&#39;,
            price: 1000,
            num: 1,
            img: &#39;img/b.jpg&#39;
          },{
            id: 3,
            name: &#39;海尔冰箱&#39;,
            price: 1000,
            num: 1,
            img: &#39;img/c.jpg&#39;
          },{
            id: 4,
            name: &#39;小米手机&#39;,
            price: 1000,
            num: 1,
            img: &#39;img/d.jpg&#39;
          },{
            id: 5,
            name: &#39;PPTV电视&#39;,
            price: 1000,
            num: 2,
            img: &#39;img/e.jpg&#39;
          }]
        }
      },
      # 3.1 从父组件把商品列表list 数据传递过来 即 父向子组件传值  
      template: `
        &lt;div class=&#39;cart&#39;&gt;
          &lt;cart-title :uname=&#39;uname&#39;&gt;&lt;/cart-title&gt;
          #  3.5  父组件通过事件绑定 接收子组件传递过来的数据 
          &lt;cart-list :list=&#39;list&#39; @cart-del=&#39;delCart($event)&#39;&gt;&lt;/cart-list&gt;
          &lt;cart-total :list=&#39;list&#39;&gt;&lt;/cart-total&gt;
        &lt;/div&gt;
      `,
      components: {
        &#39;cart-title&#39;: CartTitle,
        &#39;cart-list&#39;: CartList,
        &#39;cart-total&#39;: CartTotal
      },
      methods: {
        # 3.6    根据id删除list中对应的数据        
        delCart: function(id) {
          // 1、找到id所对应数据的索引
          var index = this.list.findIndex(item=&gt;{
            return item.id == id;
          });
          // 2、根据索引删除对应数据
          this.list.splice(index, 1);
        }
      }
    });
    var vm = new Vue({
      el: &#39;#app&#39;,
      data: {

      }
    });

  &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<h4 id="4-实现组件更新数据功能-上"><a href="#4-实现组件更新数据功能-上" class="headerlink" title="4.   实现组件更新数据功能  上"></a>4.   实现组件更新数据功能  上</h4><ul>
<li>将输入框中的默认数据动态渲染出来</li>
<li>输入框失去焦点的时候 更改商品的数量 </li>
<li>子组件中不推荐操作数据 把这些数据传递给父组件 让父组件处理这些数据</li>
<li>父组件中接收子组件传递过来的数据并处理 </li>
</ul>
<pre><code class="html"> &lt;div id=&quot;app&quot;&gt;
    &lt;div class=&quot;container&quot;&gt;
      &lt;my-cart&gt;&lt;/my-cart&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;script type=&quot;text/javascript&quot; src=&quot;js/vue.js&quot;&gt;&lt;/script&gt;
  &lt;script type=&quot;text/javascript&quot;&gt;

    var CartTitle = {
      props: [&#39;uname&#39;],
      template: `
        &lt;div class=&quot;title&quot;&gt;{{uname}}的商品&lt;/div&gt;
      `
    }
    var CartList = {
      props: [&#39;list&#39;],
      template: `
        &lt;div&gt;
          &lt;div :key=&#39;item.id&#39; v-for=&#39;item in list&#39; class=&quot;item&quot;&gt;
            &lt;img :src=&quot;item.img&quot;/&gt;
            &lt;div class=&quot;name&quot;&gt;{{item.name}}&lt;/div&gt;
            &lt;div class=&quot;change&quot;&gt;
              &lt;a href=&quot;&quot;&gt;－&lt;/a&gt;
                # 1. 将输入框中的默认数据动态渲染出来
                # 2. 输入框失去焦点的时候 更改商品的数量  需要将当前商品的id 传递过来
              &lt;input type=&quot;text&quot; class=&quot;num&quot; :value=&#39;item.num&#39; @blur=&#39;changeNum(item.id, $event)&#39;/&gt;
              &lt;a href=&quot;&quot;&gt;＋&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;del&quot; @click=&#39;del(item.id)&#39;&gt;×&lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      `,
      methods: {
        changeNum: function(id, event){
          # 3 子组件中不推荐操作数据  因为别的组件可能也引用了这些数据
          #  把这些数据传递给父组件 让父组件处理这些数据
          this.$emit(&#39;change-num&#39;, {
            id: id,
            num: event.target.value
          });
        },
        del: function(id){
          // 把id传递给父组件
          this.$emit(&#39;cart-del&#39;, id);
        }
      }
    }
    var CartTotal = {
      props: [&#39;list&#39;],
      template: `
        &lt;div class=&quot;total&quot;&gt;
          &lt;span&gt;总价：{{total}}&lt;/span&gt;
          &lt;button&gt;结算&lt;/button&gt;
        &lt;/div&gt;
      `,
      computed: {
        total: function() {
          // 计算商品的总价
          var t = 0;
          this.list.forEach(item =&gt; {
            t += item.price * item.num;
          });
          return t;
        }
      }
    }
    Vue.component(&#39;my-cart&#39;,{
      data: function() {
        return {
          uname: &#39;张三&#39;,
          list: [{
            id: 1,
            name: &#39;TCL彩电&#39;,
            price: 1000,
            num: 1,
            img: &#39;img/a.jpg&#39;
          }]
      },
      template: `
        &lt;div class=&#39;cart&#39;&gt;
          &lt;cart-title :uname=&#39;uname&#39;&gt;&lt;/cart-title&gt;
            # 4  父组件中接收子组件传递过来的数据 
          &lt;cart-list :list=&#39;list&#39; @change-num=&#39;changeNum($event)&#39; @cart-del=&#39;delCart($event)&#39;&gt;&lt;/cart-list&gt;
          &lt;cart-total :list=&#39;list&#39;&gt;&lt;/cart-total&gt;
        &lt;/div&gt;
      `,
      components: {
        &#39;cart-title&#39;: CartTitle,
        &#39;cart-list&#39;: CartList,
        &#39;cart-total&#39;: CartTotal
      },
      methods: {
        changeNum: function(val) {
          //4.1 根据子组件传递过来的数据，跟新list中对应的数据
          this.list.some(item=&gt;{
            if(item.id == val.id) {
              item.num = val.num;
              // 终止遍历
              return true;
            }
          });
        },
        delCart: function(id) {
          // 根据id删除list中对应的数据
          // 1、找到id所对应数据的索引
          var index = this.list.findIndex(item=&gt;{
            return item.id == id;
          });
          // 2、根据索引删除对应数据
          this.list.splice(index, 1);
        }
      }
    });
    var vm = new Vue({
      el: &#39;#app&#39;,
      data: {

      }
    });

  &lt;/script&gt;</code></pre>
<h4 id="5-实现组件更新数据功能-下"><a href="#5-实现组件更新数据功能-下" class="headerlink" title="5. 实现组件更新数据功能  下"></a>5. 实现组件更新数据功能  下</h4><ul>
<li>子组件通过一个标识符来标记对用的用户点击  + - 或者输入框输入的内容</li>
<li>父组件拿到标识符更新对应的组件</li>
</ul>
<pre><code class="html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot;&gt;
  &lt;title&gt;Document&lt;/title&gt;
  &lt;style type=&quot;text/css&quot;&gt;
    .container {
    }
    .container .cart {
      width: 300px;
      margin: auto;
    }
    .container .title {
      background-color: lightblue;
      height: 40px;
      line-height: 40px;
      text-align: center;
      /*color: #fff;*/  
    }
    .container .total {
      background-color: #FFCE46;
      height: 50px;
      line-height: 50px;
      text-align: right;
    }
    .container .total button {
      margin: 0 10px;
      background-color: #DC4C40;
      height: 35px;
      width: 80px;
      border: 0;
    }
    .container .total span {
      color: red;
      font-weight: bold;
    }
    .container .item {
      height: 55px;
      line-height: 55px;
      position: relative;
      border-top: 1px solid #ADD8E6;
    }
    .container .item img {
      width: 45px;
      height: 45px;
      margin: 5px;
    }
    .container .item .name {
      position: absolute;
      width: 90px;
      top: 0;left: 55px;
      font-size: 16px;
    }

    .container .item .change {
      width: 100px;
      position: absolute;
      top: 0;
      right: 50px;
    }
    .container .item .change a {
      font-size: 20px;
      width: 30px;
      text-decoration:none;
      background-color: lightgray;
      vertical-align: middle;
    }
    .container .item .change .num {
      width: 40px;
      height: 25px;
    }
    .container .item .del {
      position: absolute;
      top: 0;
      right: 0px;
      width: 40px;
      text-align: center;
      font-size: 40px;
      cursor: pointer;
      color: red;
    }
    .container .item .del:hover {
      background-color: orange;
    }
  &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;div id=&quot;app&quot;&gt;
    &lt;div class=&quot;container&quot;&gt;
      &lt;my-cart&gt;&lt;/my-cart&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;script type=&quot;text/javascript&quot; src=&quot;js/vue.js&quot;&gt;&lt;/script&gt;
  &lt;script type=&quot;text/javascript&quot;&gt;

    var CartTitle = {
      props: [&#39;uname&#39;],
      template: `
        &lt;div class=&quot;title&quot;&gt;{{uname}}的商品&lt;/div&gt;
      `
    }
    var CartList = {
      props: [&#39;list&#39;],
      template: `
        &lt;div&gt;
          &lt;div :key=&#39;item.id&#39; v-for=&#39;item in list&#39; class=&quot;item&quot;&gt;
            &lt;img :src=&quot;item.img&quot;/&gt;
            &lt;div class=&quot;name&quot;&gt;{{item.name}}&lt;/div&gt;
            &lt;div class=&quot;change&quot;&gt;
              # 1.  + - 按钮绑定事件 
              &lt;a href=&quot;&quot; @click.prevent=&#39;sub(item.id)&#39;&gt;－&lt;/a&gt;
              &lt;input type=&quot;text&quot; class=&quot;num&quot; :value=&#39;item.num&#39; @blur=&#39;changeNum(item.id, $event)&#39;/&gt;
              &lt;a href=&quot;&quot; @click.prevent=&#39;add(item.id)&#39;&gt;＋&lt;/a&gt;
            &lt;/div&gt;
            &lt;div class=&quot;del&quot; @click=&#39;del(item.id)&#39;&gt;×&lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      `,
      methods: {
        changeNum: function(id, event){
          this.$emit(&#39;change-num&#39;, {
            id: id,
            type: &#39;change&#39;,
            num: event.target.value
          });
        },
        sub: function(id){
          # 2 数量的增加和减少通过父组件来计算   每次都是加1 和 减1 不需要传递数量   父组件需要一个类型来判断 是 加一 还是减1  以及是输入框输入的数据  我们通过type 标识符来标记 不同的操作   
          this.$emit(&#39;change-num&#39;, {
            id: id,
            type: &#39;sub&#39;
          });
        },
        add: function(id){
         # 2 数量的增加和减少通过父组件来计算   每次都是加1 和 减1 不需要传递数量   父组件需要一个类型来判断 是 加一 还是减1  以及是输入框输入的数据  我们通过type 标识符来标记 不同的操作
          this.$emit(&#39;change-num&#39;, {
            id: id,
            type: &#39;add&#39;
          });
        },
        del: function(id){
          // 把id传递给父组件
          this.$emit(&#39;cart-del&#39;, id);
        }
      }
    }
    var CartTotal = {
      props: [&#39;list&#39;],
      template: `
        &lt;div class=&quot;total&quot;&gt;
          &lt;span&gt;总价：{{total}}&lt;/span&gt;
          &lt;button&gt;结算&lt;/button&gt;
        &lt;/div&gt;
      `,
      computed: {
        total: function() {
          // 计算商品的总价
          var t = 0;
          this.list.forEach(item =&gt; {
            t += item.price * item.num;
          });
          return t;
        }
      }
    }
    Vue.component(&#39;my-cart&#39;,{
      data: function() {
        return {
          uname: &#39;张三&#39;,
          list: [{
            id: 1,
            name: &#39;TCL彩电&#39;,
            price: 1000,
            num: 1,
            img: &#39;img/a.jpg&#39;
          },{
            id: 2,
            name: &#39;机顶盒&#39;,
            price: 1000,
            num: 1,
            img: &#39;img/b.jpg&#39;
          },{
            id: 3,
            name: &#39;海尔冰箱&#39;,
            price: 1000,
            num: 1,
            img: &#39;img/c.jpg&#39;
          },{
            id: 4,
            name: &#39;小米手机&#39;,
            price: 1000,
            num: 1,
            img: &#39;img/d.jpg&#39;
          },{
            id: 5,
            name: &#39;PPTV电视&#39;,
            price: 1000,
            num: 2,
            img: &#39;img/e.jpg&#39;
          }]
        }
      },
      template: `
        &lt;div class=&#39;cart&#39;&gt;
          &lt;cart-title :uname=&#39;uname&#39;&gt;&lt;/cart-title&gt;    
        # 3 父组件通过事件监听   接收子组件的数据  
          &lt;cart-list :list=&#39;list&#39; @change-num=&#39;changeNum($event)&#39; @cart-del=&#39;delCart($event)&#39;&gt;&lt;/cart-list&gt;
          &lt;cart-total :list=&#39;list&#39;&gt;&lt;/cart-total&gt;
        &lt;/div&gt;
      `,
      components: {
        &#39;cart-title&#39;: CartTitle,
        &#39;cart-list&#39;: CartList,
        &#39;cart-total&#39;: CartTotal
      },
      methods: {
        changeNum: function(val) {
          #4 分为三种情况：输入框变更、加号变更、减号变更
          if(val.type==&#39;change&#39;) {
            // 根据子组件传递过来的数据，跟新list中对应的数据
            this.list.some(item=&gt;{
              if(item.id == val.id) {
                item.num = val.num;
                // 终止遍历
                return true;
              }
            });
          }else if(val.type==&#39;sub&#39;){
            // 减一操作
            this.list.some(item=&gt;{
              if(item.id == val.id) {
                item.num -= 1;
                // 终止遍历
                return true;
              }
            });
          }else if(val.type==&#39;add&#39;){
            // 加一操作
            this.list.some(item=&gt;{
              if(item.id == val.id) {
                item.num += 1;
                // 终止遍历
                return true;
              }
            });
          }
        }
      }
    });
    var vm = new Vue({
      el: &#39;#app&#39;,
      data: {

      }
    });

  &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<h2 id="day04"><a href="#day04" class="headerlink" title="day04"></a>day04</h2><h3 id="接口调用方式"><a href="#接口调用方式" class="headerlink" title="接口调用方式"></a>接口调用方式</h3><ul>
<li>原生ajax（麻烦）</li>
<li>基于jQuery的ajax（DOM操作）</li>
<li>fetch（标准化组织制定的新的规范）</li>
<li>axios（第三方库，更方便）</li>
</ul>
<p>Restful形式的URL </p>
<p>HTTP请求方式</p>
<ul>
<li>GET查询</li>
<li>POST添加</li>
<li>PUT修改</li>
<li>DELETE删除</li>
</ul>
<pre><code>符合规则的URL地址

http://www.hello.com/books GET

http://www.hello.com/books POST

http://www.hello.com/books/123 PUT

http://www.hello.com/books/123 DELETE</code></pre><h3 id="异步"><a href="#异步" class="headerlink" title="异步"></a>异步</h3><ul>
<li>JavaScript的执行环境是「单线程」</li>
<li>所谓单线程，是指JS引擎中负责解释和执行JavaScript代码的线程只有一个，也就是一次只能完成一项任务，这个任务执行完后才能执行下一个，它会「阻塞」其他任务。这个任务可称为主线程</li>
<li>异步模式可以一起执行<strong>多个任务</strong></li>
<li>JS中常见的异步调用<ul>
<li>定时任务</li>
<li>ajax</li>
<li>事件函数</li>
</ul>
</li>
</ul>
<p>多次异步调用的依赖分析</p>
<ul>
<li>多次异步调用的结果顺序不确定</li>
<li>异步调用结果如果存在依赖需要嵌套（回调地狱）</li>
</ul>
<h3 id="promise"><a href="#promise" class="headerlink" title="promise"></a>promise</h3><ul>
<li>主要解决异步深层嵌套的问题（回调地狱）</li>
<li>promise 提供了简洁的API  使得异步操作更加容易</li>
</ul>
<pre><code class="html">
  &lt;script type=&quot;text/javascript&quot;&gt;
    /*1. Promise基本使用
           我们使用new来构建一个Promise  Promise的构造函数接收一个参数，是函数，并且传入两个参数：           resolve，reject， 分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数
    */
    var p = new Promise(function(resolve, reject){
      //2. 这里用于实现异步任务  setTimeout
      setTimeout(function(){
        var flag = false;
        if(flag) {
          //3. 正常情况
          resolve(&#39;hello&#39;);
        }else{
          //4. 异常情况
          reject(&#39;出错了&#39;);
        }
      }, 100);
    });
    //  5 Promise实例生成以后，可以用then方法指定resolved状态和reject状态的回调函数 
    //  在then方法中，你也可以直接return数据而不是Promise对象，在后面的then中就可以接收到数据了  
    p.then(function(data){
      console.log(data)
    },function(info){
      console.log(info)
    });
  &lt;/script&gt;</code></pre>
<h3 id="基于Promise发送Ajax请求"><a href="#基于Promise发送Ajax请求" class="headerlink" title="基于Promise发送Ajax请求"></a>基于Promise发送Ajax请求</h3><pre><code class="html">
  &lt;script type=&quot;text/javascript&quot;&gt;
    /*
      基于Promise发送Ajax请求
    */
    function queryData(url) {
     //1.1 创建一个Promise实例
      var p = new Promise(function(resolve, reject){
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function(){
          if(xhr.readyState != 4) return;
          if(xhr.readyState == 4 &amp;&amp; xhr.status == 200) {
            // 1.2 处理正常的情况
            resolve(xhr.responseText);
          }else{
            //1.3 处理异常情况
            reject(&#39;服务器错误&#39;);
          }
        };
        xhr.open(&#39;get&#39;, url);
        xhr.send(null);
      });
      return p;
    }
    //注意：  这里需要开启一个服务 
   //在then方法中，你也可以直接return数据而不是Promise对象，在后面的then中就可以接收到数据了
    queryData(&#39;http://localhost:3000/data&#39;)
      .then(function(data){
        console.log(data)
        //1.4 想要继续链式编程下去 需要 return  
        return queryData(&#39;http://localhost:3000/data1&#39;);
      })
      .then(function(data){
        console.log(data);
        return queryData(&#39;http://localhost:3000/data2&#39;);
      })
      .then(function(data){
        console.log(data)
      });
  &lt;/script&gt;</code></pre>
<h3 id="Promise-基本API"><a href="#Promise-基本API" class="headerlink" title="Promise  基本API"></a>Promise  基本API</h3><h4 id="实例方法"><a href="#实例方法" class="headerlink" title="实例方法"></a>实例方法</h4><h5 id="then"><a href="#then" class="headerlink" title=".then()"></a>.then()</h5><ul>
<li>得到异步任务正确的结果</li>
</ul>
<h5 id="catch"><a href="#catch" class="headerlink" title=".catch()"></a>.catch()</h5><ul>
<li>获取异常信息</li>
</ul>
<h5 id="finally"><a href="#finally" class="headerlink" title=".finally()"></a>.finally()</h5><ul>
<li>成功与否都会执行（不是正式标准） </li>
</ul>
<pre><code class="html">
  &lt;script type=&quot;text/javascript&quot;&gt;
    /*
      Promise常用API-实例方法
    */
    // console.dir(Promise);
    function foo() {
      return new Promise(function(resolve, reject){
        setTimeout(function(){
          // resolve(123);
          reject(&#39;error&#39;);
        }, 100);
      })
    }
    // foo()
    //   .then(function(data){
    //     console.log(data)
    //   })
    //   .catch(function(data){
    //     console.log(data)
    //   })
    //   .finally(function(){
    //     console.log(&#39;finished&#39;)
    //   });

    // --------------------------
    // 两种写法是等效的
    foo()
      .then(function(data){
        # 得到异步任务正确的结果
        console.log(data)
      },function(data){
        # 获取异常信息
        console.log(data)
      })
      # 成功与否都会执行（不是正式标准） 
      .finally(function(){
        console.log(&#39;finished&#39;)
      });
  &lt;/script&gt;</code></pre>
<h4 id="对象方法"><a href="#对象方法" class="headerlink" title="对象方法"></a>对象方法</h4><h5 id="Promise-all"><a href="#Promise-all" class="headerlink" title="Promise.all( )"></a>Promise.all( )</h5><ul>
<li>并发处理多个异步任务，所有任务都执完成才能得到结果</li>
<li><code>Promise.all</code>方法接受一个数组作参数，数组中的对象（p1、p2、p3）均为promise实例（如果不是一个promise，该项会被用<code>Promise.resolve</code>转换为一个promise)。它的状态由这三个promise实例决定</li>
</ul>
<h5 id="Promise-race"><a href="#Promise-race" class="headerlink" title="Promise.race( )"></a>Promise.race( )</h5><ul>
<li>并发处理多个异步任务，只要有一个任务完成就能得到结果</li>
<li><code>Promise.race</code>方法同样接受一个数组作参数。当p1, p2, p3中有一个实例的状态发生改变（变为<code>fulfilled</code>或<code>rejected</code>），p的状态就跟着改变。并把第一个改变状态的promise的返回值，传给p的回调函数</li>
</ul>
<pre><code class="html">  &lt;script type=&quot;text/javascript&quot;&gt;
    /*
      Promise常用API-对象方法
    */
    // console.dir(Promise)
    function queryData(url) {
      return new Promise(function(resolve, reject){
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function(){
          if(xhr.readyState != 4) return;
          if(xhr.readyState == 4 &amp;&amp; xhr.status == 200) {
            // 处理正常的情况
            resolve(xhr.responseText);
          }else{
            // 处理异常情况
            reject(&#39;服务器错误&#39;);
          }
        };
        xhr.open(&#39;get&#39;, url);
        xhr.send(null);
      });
    }

    var p1 = queryData(&#39;http://localhost:3000/a1&#39;);
    var p2 = queryData(&#39;http://localhost:3000/a2&#39;);
    var p3 = queryData(&#39;http://localhost:3000/a3&#39;);
     Promise.all([p1,p2,p3]).then(function(result){
       //   all 中的参数  [p1,p2,p3]   和 返回的结果一 一对应[&quot;HELLO TOM&quot;, &quot;HELLO JERRY&quot;, &quot;HELLO SPIKE&quot;]
       console.log(result) //[&quot;HELLO TOM&quot;, &quot;HELLO JERRY&quot;, &quot;HELLO SPIKE&quot;]
     })
    Promise.race([p1,p2,p3]).then(function(result){
      // 由于p1执行较快，Promise的then()将获得结果&#39;P1&#39;。p2,p3仍在继续执行，但执行结果将被丢弃。
      console.log(result) // &quot;HELLO TOM&quot;
    })
  &lt;/script&gt;</code></pre>
<h3 id="fetch"><a href="#fetch" class="headerlink" title="fetch"></a>fetch</h3><ul>
<li>Fetch API是新的ajax解决方案,基于Promise实现， Fetch会返回Promise</li>
<li>fetch不是ajax的进一步封装，而是原生js，没有使用XMLHttpRequest对象。</li>
<li>fetch(url, options).then(）</li>
</ul>
<pre><code class="html">  &lt;script type=&quot;text/javascript&quot;&gt;
    /*
      Fetch API 基本用法
          fetch(url).then()
         第一个参数请求的路径   Fetch会返回Promise   所以我们可以使用then 拿到请求成功的结果 
    */
    fetch(&#39;http://localhost:3000/fdata&#39;).then(function(data){
      // text()方法属于fetchAPI的一部分，它返回一个Promise实例对象，用于获取后台返回的数据
      return data.text();
    }).then(function(data){
      //   在这个then里面我们能拿到最终的数据  
      console.log(data);
    })
  &lt;/script&gt;</code></pre>
<h4 id="fetch-API-中的-HTTP-请求"><a href="#fetch-API-中的-HTTP-请求" class="headerlink" title="fetch API  中的 HTTP  请求"></a>fetch API  中的 HTTP  请求</h4><ul>
<li>fetch(url, options).then(）</li>
<li>HTTP协议，它给我们提供了很多的方法，如POST，GET，DELETE，UPDATE，PATCH和PUT<ul>
<li>默认的是 GET 请求</li>
<li>需要在 options 对象中 指定对应的 method       method:请求使用的方法 </li>
<li>post 和 普通 请求的时候 需要在options 中 设置  请求头 headers   和  body</li>
</ul>
</li>
</ul>
<pre><code class="html">   &lt;script type=&quot;text/javascript&quot;&gt;
        /*
              Fetch API 调用接口传递参数
        */
       #1.1 GET参数传递 - 传统URL  通过url  ？ 的形式传参 
        fetch(&#39;http://localhost:3000/books?id=123&#39;, {
                # get 请求可以省略不写 默认的是GET 
                method: &#39;get&#39;
            })
            .then(function(data) {
                # 它返回一个Promise实例对象，用于获取后台返回的数据
                return data.text();
            }).then(function(data) {
                # 在这个then里面我们能拿到最终的数据  
                console.log(data)
            });

      #1.2  GET参数传递  restful形式的URL  通过/ 的形式传递参数  即  id = 456 和id后台的配置有关   
        fetch(&#39;http://localhost:3000/books/456&#39;, {
                # get 请求可以省略不写 默认的是GET 
                method: &#39;get&#39;
            })
            .then(function(data) {
                return data.text();
            }).then(function(data) {
                console.log(data)
            });

       #2.1  DELETE请求方式参数传递      删除id  是  id=789
        fetch(&#39;http://localhost:3000/books/789&#39;, {
                method: &#39;delete&#39;
            })
            .then(function(data) {
                return data.text();
            }).then(function(data) {
                console.log(data)
            });

       #3 POST请求传参
        fetch(&#39;http://localhost:3000/books&#39;, {
                method: &#39;post&#39;,
                # 3.1  传递数据 
                body: &#39;uname=lisi&amp;pwd=123&#39;,
                #  3.2  设置请求头 
                headers: {
                    &#39;Content-Type&#39;: &#39;application/x-www-form-urlencoded&#39;
                }
            })
            .then(function(data) {
                return data.text();
            }).then(function(data) {
                console.log(data)
            });

       # POST请求传参
        fetch(&#39;http://localhost:3000/books&#39;, {
                method: &#39;post&#39;,
                body: JSON.stringify({
                    uname: &#39;张三&#39;,
                    pwd: &#39;456&#39;
                }),
                headers: {
                    &#39;Content-Type&#39;: &#39;application/json&#39;
                }
            })
            .then(function(data) {
                return data.text();
            }).then(function(data) {
                console.log(data)
            });

        # PUT请求传参     修改id 是 123 的 
        fetch(&#39;http://localhost:3000/books/123&#39;, {
                method: &#39;put&#39;,
                body: JSON.stringify({
                    uname: &#39;张三&#39;,
                    pwd: &#39;789&#39;
                }),
                headers: {
                    &#39;Content-Type&#39;: &#39;application/json&#39;
                }
            })
            .then(function(data) {
                return data.text();
            }).then(function(data) {
                console.log(data)
            });
    &lt;/script&gt;</code></pre>
<h4 id="fetchAPI-中-响应格式"><a href="#fetchAPI-中-响应格式" class="headerlink" title="fetchAPI 中 响应格式"></a>fetchAPI 中 响应格式</h4><ul>
<li>用fetch来获取数据，如果响应正常返回，我们首先看到的是一个response对象，其中包括返回的一堆原始字节，这些字节需要在收到后，需要我们通过调用方法将其转换为相应格式的数据，比如<code>JSON</code>，<code>BLOB</code>或者<code>TEXT</code>等等</li>
</ul>
<pre><code class="js">
    /*
      Fetch响应结果的数据格式
    */
    fetch(&#39;http://localhost:3000/json&#39;).then(function(data){
      // return data.json();   //  将获取到的数据使用 json 转换对象
      return data.text(); //  //  将获取到的数据 转换成字符串 
    }).then(function(data){
      // console.log(data.uname)
      // console.log(typeof data)
      var obj = JSON.parse(data);
      console.log(obj.uname,obj.age,obj.gender)
    })
</code></pre>
<h3 id="axios"><a href="#axios" class="headerlink" title="axios"></a>axios</h3><ul>
<li>基于promise用于浏览器和node.js的http客户端</li>
<li>支持浏览器和node.js</li>
<li>支持promise</li>
<li>能拦截请求和响应</li>
<li>自动转换JSON数据</li>
<li>能转换请求和响应数据</li>
</ul>
<h4 id="axios基础用法"><a href="#axios基础用法" class="headerlink" title="axios基础用法"></a>axios基础用法</h4><ul>
<li>get和 delete请求传递参数<ul>
<li>通过传统的url  以 ? 的形式传递参数</li>
<li>restful 形式传递参数 </li>
<li>通过params  形式传递参数 </li>
</ul>
</li>
<li>post  和 put  请求传递参数<ul>
<li>通过选项传递参数</li>
<li>通过 URLSearchParams  传递参数 </li>
</ul>
</li>
</ul>
<pre><code class="js">    # 1. 发送get 请求 
    axios.get(&#39;http://localhost:3000/adata&#39;).then(function(ret){ 
      #  拿到 ret 是一个对象      所有的对象都存在 ret 的data 属性里面
      // 注意data属性是固定的用法，用于获取后台的实际数据
      // console.log(ret.data)
      console.log(ret)
    })
    # 2.  get 请求传递参数
    # 2.1  通过传统的url  以 ? 的形式传递参数
    axios.get(&#39;http://localhost:3000/axios?id=123&#39;).then(function(ret){
      console.log(ret.data)
    })
    # 2.2  restful 形式传递参数 
    axios.get(&#39;http://localhost:3000/axios/123&#39;).then(function(ret){
      console.log(ret.data)
    })
    # 2.3  通过params  形式传递参数 
    axios.get(&#39;http://localhost:3000/axios&#39;, {
      params: {
        id: 789
      }
    }).then(function(ret){
      console.log(ret.data)
    })
    #3 axios delete 请求传参     传参的形式和 get 请求一样
    axios.delete(&#39;http://localhost:3000/axios&#39;, {
      params: {
        id: 111
      }
    }).then(function(ret){
      console.log(ret.data)
    })

    # 4  axios 的 post 请求
    # 4.1  通过选项传递参数
    axios.post(&#39;http://localhost:3000/axios&#39;, {
      uname: &#39;lisi&#39;,
      pwd: 123
    }).then(function(ret){
      console.log(ret.data)
    })
    # 4.2  通过 URLSearchParams  传递参数 
    var params = new URLSearchParams();
    params.append(&#39;uname&#39;, &#39;zhangsan&#39;);
    params.append(&#39;pwd&#39;, &#39;111&#39;);
    axios.post(&#39;http://localhost:3000/axios&#39;, params).then(function(ret){
      console.log(ret.data)
    })

     #5  axios put 请求传参   和 post 请求一样 
    axios.put(&#39;http://localhost:3000/axios/123&#39;, {
      uname: &#39;lisi&#39;,
      pwd: 123
    }).then(function(ret){
      console.log(ret.data)
    })
</code></pre>
<h4 id="axios-全局配置"><a href="#axios-全局配置" class="headerlink" title="axios 全局配置"></a>axios 全局配置</h4><pre><code class="js">#  配置公共的请求头 
axios.defaults.baseURL = &#39;https://api.example.com&#39;;
#  配置 超时时间
axios.defaults.timeout = 2500;
#  配置公共的请求头
axios.defaults.headers.common[&#39;Authorization&#39;] = AUTH_TOKEN;
# 配置公共的 post 的 Content-Type
axios.defaults.headers.post[&#39;Content-Type&#39;] = &#39;application/x-www-form-urlencoded&#39;;

</code></pre>
<h4 id="axios-拦截器"><a href="#axios-拦截器" class="headerlink" title="axios 拦截器"></a>axios 拦截器</h4><ul>
<li>请求拦截器<ul>
<li>请求拦截器的作用是在请求发送前进行一些操作<ul>
<li>例如在每个请求体里加上token，统一做了处理如果以后要改也非常容易</li>
</ul>
</li>
</ul>
</li>
<li>响应拦截器<ul>
<li>响应拦截器的作用是在接收到响应后进行一些操作<ul>
<li>例如在服务器返回登录状态失效，需要重新登录的时候，跳转到登录页</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code class="js">    # 1. 请求拦截器 
    axios.interceptors.request.use(function(config) {
      console.log(config.url)
      # 1.1  任何请求都会经过这一步   在发送请求之前做些什么   
      config.headers.mytoken = &#39;nihao&#39;;
      # 1.2  这里一定要return   否则配置不成功  
      return config;
    }, function(err){
       #1.3 对请求错误做点什么    
      console.log(err)
    })
    #2. 响应拦截器 
    axios.interceptors.response.use(function(res) {
      #2.1  在接收响应做些什么  
      var data = res.data;
      return data;
    }, function(err){
      #2.2 对响应错误做点什么  
      console.log(err)
    })</code></pre>
<h3 id="async-和-await"><a href="#async-和-await" class="headerlink" title="async  和 await"></a>async  和 await</h3><ul>
<li>async作为一个关键字放到函数前面<ul>
<li>任何一个<code>async</code>函数都会隐式返回一个<code>promise</code></li>
</ul>
</li>
<li><code>await</code>关键字只能在使用<code>async</code>定义的函数中使用<ul>
<li>​    await后面可以直接跟一个 Promise实例对象</li>
<li>​     await函数不能单独使用</li>
</ul>
</li>
<li><strong>async/await 让异步代码看起来、表现起来更像同步代码</strong></li>
</ul>
<pre><code class="js">     # 1.  async 基础用法
    # 1.1 async作为一个关键字放到函数前面
    async function queryData() {
      # 1.2 await关键字只能在使用async定义的函数中使用      await后面可以直接跟一个 Promise实例对象
      var ret = await new Promise(function(resolve, reject){
        setTimeout(function(){
          resolve(&#39;nihao&#39;)
        },1000);
      })
      // console.log(ret.data)
      return ret;
    }
    # 1.3 任何一个async函数都会隐式返回一个promise   我们可以使用then 进行链式编程
    queryData().then(function(data){
      console.log(data)
    })

    #2.  async    函数处理多个异步函数
    axios.defaults.baseURL = &#39;http://localhost:3000&#39;;

    async function queryData() {
      # 2.1  添加await之后 当前的await 返回结果之后才会执行后面的代码   

      var info = await axios.get(&#39;async1&#39;);
      #2.2  让异步代码看起来、表现起来更像同步代码
      var ret = await axios.get(&#39;async2?info=&#39; + info.data);
      return ret.data;
    }

    queryData().then(function(data){
      console.log(data)
    })</code></pre>
<h3 id="图书列表案例-1"><a href="#图书列表案例-1" class="headerlink" title="图书列表案例"></a>图书列表案例</h3><h4 id="1-基于接口案例-获取图书列表"><a href="#1-基于接口案例-获取图书列表" class="headerlink" title="1. 基于接口案例-获取图书列表"></a>1. 基于接口案例-获取图书列表</h4><ul>
<li>导入axios   用来发送ajax </li>
<li>把获取到的数据渲染到页面上 </li>
</ul>
<pre><code class="html">  &lt;div id=&quot;app&quot;&gt;
        &lt;div class=&quot;grid&quot;&gt;
            &lt;table&gt;
                &lt;thead&gt;
                    &lt;tr&gt;
                        &lt;th&gt;编号&lt;/th&gt;
                        &lt;th&gt;名称&lt;/th&gt;
                        &lt;th&gt;时间&lt;/th&gt;
                        &lt;th&gt;操作&lt;/th&gt;
                    &lt;/tr&gt;
                &lt;/thead&gt;
                &lt;tbody&gt;
                    &lt;!-- 5.  把books  中的数据渲染到页面上   --&gt;
                    &lt;tr :key=&#39;item.id&#39; v-for=&#39;item in books&#39;&gt;
                        &lt;td&gt;{{item.id}}&lt;/td&gt;
                        &lt;td&gt;{{item.name}}&lt;/td&gt;
                        &lt;td&gt;{{item.date }}&lt;/td&gt;
                        &lt;td&gt;
                            &lt;a href=&quot;&quot;&gt;修改&lt;/a&gt;
                            &lt;span&gt;|&lt;/span&gt;
                            &lt;a href=&quot;&quot;&gt;删除&lt;/a&gt;
                        &lt;/td&gt;
                    &lt;/tr&gt;
                &lt;/tbody&gt;
            &lt;/table&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    &lt;script type=&quot;text/javascript&quot; src=&quot;js/vue.js&quot;&gt;&lt;/script&gt;
    1.  导入axios   
    &lt;script type=&quot;text/javascript&quot; src=&quot;js/axios.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/javascript&quot;&gt;
        /*
             图书管理-添加图书
         */
        # 2   配置公共的url地址  简化后面的调用方式
        axios.defaults.baseURL = &#39;http://localhost:3000/&#39;;
        axios.interceptors.response.use(function(res) {
            return res.data;
        }, function(error) {
            console.log(error)
        });

        var vm = new Vue({
            el: &#39;#app&#39;,
            data: {
                flag: false,
                submitFlag: false,
                id: &#39;&#39;,
                name: &#39;&#39;,
                books: []
            },
            methods: {
                # 3 定义一个方法 用来发送 ajax 
                # 3.1  使用 async  来 让异步的代码  以同步的形式书写 
                queryData: async function() {
                    // 调用后台接口获取图书列表数据
                    // var ret = await axios.get(&#39;books&#39;);
                    // this.books = ret.data;
                    # 3.2  发送ajax请求  把拿到的数据放在books 里面   
                    this.books = await axios.get(&#39;books&#39;);
                }
            },

            mounted: function() {
                #  4 mounted  里面 DOM已经加载完毕  在这里调用函数  
                this.queryData();
            }
        });
    &lt;/script&gt;</code></pre>
<h4 id="2-添加图书"><a href="#2-添加图书" class="headerlink" title="2   添加图书"></a>2   添加图书</h4><ul>
<li>获取用户输入的数据   发送到后台</li>
<li>渲染最新的数据到页面上</li>
</ul>
<pre><code class="js"> methods: {
    handle: async function(){
          if(this.flag) {
            // 编辑图书
            // 就是根据当前的ID去更新数组中对应的数据
            this.books.some((item) =&gt; {
              if(item.id == this.id) {
                item.name = this.name;
                // 完成更新操作之后，需要终止循环
                return true;
              }
            });
            this.flag = false;
          }else{
            # 1.1  在前面封装好的 handle 方法中  发送ajax请求  
            # 1.2  使用async  和 await 简化操作 需要在 function 前面添加 async   
            var ret = await axios.post(&#39;books&#39;, {
              name: this.name
            })
            # 1.3  根据后台返回的状态码判断是否加载数据 
            if(ret.status == 200) {
             # 1.4  调用 queryData 这个方法  渲染最新的数据 
              this.queryData();
            }
          }
          // 清空表单
          this.id = &#39;&#39;;
          this.name = &#39;&#39;;
        },        
 }         </code></pre>
<h4 id="3-验证图书名称是否存在"><a href="#3-验证图书名称是否存在" class="headerlink" title="3  验证图书名称是否存在"></a>3  验证图书名称是否存在</h4><ul>
<li>添加图书之前发送请求验证图示是否已经存在</li>
<li>如果不存在 往后台里面添加图书名称<ul>
<li>图书存在与否只需要修改submitFlag的值即可</li>
</ul>
</li>
</ul>
<pre><code class="js"> watch: {
        name: async function(val) {
          // 验证图书名称是否已经存在
          // var flag = this.books.some(function(item){
          //   return item.name == val;
          // });
          var ret = await axios.get(&#39;/books/book/&#39; + this.name);
          if(ret.status == 1) {
            // 图书名称存在
            this.submitFlag = true;
          }else{
            // 图书名称不存在
            this.submitFlag = false;
          }
        }
},</code></pre>
<h4 id="4-编辑图书"><a href="#4-编辑图书" class="headerlink" title="4.  编辑图书"></a>4.  编辑图书</h4><ul>
<li>根据当前书的id 查询需要编辑的书籍</li>
<li>需要根据状态位判断是添加还是编辑 </li>
</ul>
<pre><code class="js"> methods: {
        handle: async function(){
          if(this.flag) {
            #4.3 编辑图书   把用户输入的信息提交到后台
            var ret = await axios.put(&#39;books/&#39; + this.id, {
              name: this.name
            });
            if(ret.status == 200){
              #4.4  完成添加后 重新加载列表数据
              this.queryData();
            }
            this.flag = false;
          }else{
            // 添加图书
            var ret = await axios.post(&#39;books&#39;, {
              name: this.name
            })
            if(ret.status == 200) {
              // 重新加载列表数据
              this.queryData();
            }
          }
          // 清空表单
          this.id = &#39;&#39;;
          this.name = &#39;&#39;;
        },
        toEdit: async function(id){
          #4.1  flag状态位用于区分编辑和添加操作
          this.flag = true;
          #4.2  根据id查询出对应的图书信息  页面中可以加载出来最新的信息
          # 调用接口发送ajax 请求  
          var ret = await axios.get(&#39;books/&#39; + id);
          this.id = ret.id;
          this.name = ret.name;
        },</code></pre>
<h4 id="5-删除图书"><a href="#5-删除图书" class="headerlink" title="5 删除图书"></a>5 删除图书</h4><ul>
<li>把需要删除的id书籍 通过参数的形式传递到后台</li>
</ul>
<pre><code class="js">   deleteBook: async function(id){
          // 删除图书
          var ret = await axios.delete(&#39;books/&#39; + id);
          if(ret.status == 200) {
            // 重新加载列表数据
            this.queryData();
          }
   }</code></pre>
<h2 id="day-05"><a href="#day-05" class="headerlink" title="day 05"></a>day 05</h2><h3 id="路由"><a href="#路由" class="headerlink" title="路由"></a>路由</h3><p> 路由是一个比较广义和抽象的概念，路由的本质就是对应关系。 </p>
<p>在开发中，路由分为： 后端路由 和 前端路由  </p>
<p> 后端路由根据不同的URL地址分发不同的资源 ， 前端路由负责事件监听，触发事件后 ，通过事件函数渲染不同内容 </p>
<h4 id="后端路由"><a href="#后端路由" class="headerlink" title="后端路由"></a>后端路由</h4><ul>
<li>概念：根据不同的用户 URL 请求，返回不同的内容 </li>
<li>本质：URL 请求地址与服务器资源之间的对应关系 </li>
</ul>
<h5 id="SPA（Single-Page-Application）"><a href="#SPA（Single-Page-Application）" class="headerlink" title="SPA（Single Page Application）"></a>SPA（Single Page Application）</h5><ul>
<li>后端渲染（存在性能问题）</li>
<li>Ajax前端渲染（前端渲染提高性能，但是不支持浏览器的前进后退操作）</li>
<li>SPA（Single Page Application）单页面应用程序：整个网站只有一个页面，内容的变化通过Ajax局部更新实现、同时支持浏览器地址栏的前进和后退操作</li>
<li>SPA实现原理之一：基于URL地址的hash（hash的变化会导致浏览器记录访问历 史的变化、但是hash的变化不会触发新的URL请求）</li>
<li>在实现SPA过程中，最核心的技术点就是前端路由 </li>
</ul>
<h4 id="前端路由"><a href="#前端路由" class="headerlink" title="前端路由"></a>前端路由</h4><ul>
<li>概念：根据不同的用户事件，显示不同的页面内容</li>
<li>本质：用户事件与事件处理函数之间的对应关系 </li>
</ul>
<h4 id="实现简易前端路由"><a href="#实现简易前端路由" class="headerlink" title="实现简易前端路由"></a>实现简易前端路由</h4><p> 基于URL中的hash实现（点击菜单的时候改变URL的hash，根据hash的变化控制组件的切换） </p>
<p>![](<a href="http://helloxx.cn/d5" target="_blank" rel="noopener">http://helloxx.cn/d5</a> (1).png)</p>
<pre><code class="js">// 监听 window 的 onhashchange 事件，根据获取到的最新的 hash 值，切换要显示的组件的名称
window.onhashchange = function() {
 // 通过 location.hash 获取到最新的 hash 值
}</code></pre>
<h3 id="Vue-Router"><a href="#Vue-Router" class="headerlink" title="Vue Router"></a>Vue Router</h3><p>Vue Router（官网：<code>https://router.vuejs.org/zh/</code>）是 Vue.js 官方的路由管理器。 它和 Vue.js 的核心深度集成，可以非常方便的用于SPA应用程序的开发。  </p>
<p> Vue Router 包含的功能有： </p>
<ul>
<li>支持HTML5 历史模式或 hash 模式</li>
<li>支持嵌套路由</li>
<li>支持路由参数</li>
<li>支持编程式路由</li>
<li>支持命名路由 </li>
</ul>
<h4 id="Vue-Router-基本使用"><a href="#Vue-Router-基本使用" class="headerlink" title="Vue Router 基本使用"></a>Vue Router 基本使用</h4><p>步骤 </p>
<ol>
<li>引入相关的库文件</li>
<li>添加路由链接 </li>
<li>添加路由填充位</li>
<li>定义路由组件</li>
<li>配置路由规则并创建路由实例</li>
<li>把路由挂载到 Vue 根实例中 </li>
</ol>
<p>1.引入相关的库文件 </p>
<pre><code class="html">&lt;!-- 导入 vue 文件，为全局 window 对象挂载 Vue 构造函数 --&gt;
&lt;script src=&quot;./lib/vue_2.5.22.js&quot;&gt;&lt;/script&gt;
&lt;!-- 导入 vue-router 文件，为全局 window 对象挂载 VueRouter 构造函数 --&gt;
&lt;script src=&quot;./lib/vue-router_3.0.2.js&quot;&gt;&lt;/script&gt;</code></pre>
<p>2.添加路由链接 </p>
<pre><code class="html">&lt;!-- router-link 是 vue 中提供的标签，默认会被渲染为 a 标签 --&gt;
&lt;!-- to 属性默认会被渲染为 href 属性 --&gt;
&lt;!-- to 属性的值默认会被渲染为 # 开头的 hash 地址 --&gt;
&lt;router-link to=&quot;/user&quot;&gt;User&lt;/router-link&gt;
&lt;router-link to=&quot;/register&quot;&gt;Register&lt;/router-link&gt;</code></pre>
<p>3.添加路由填充位 </p>
<pre><code class="html">&lt;!-- 路由填充位（也叫做路由占位符） --&gt;
&lt;!-- 将来通过路由规则匹配到的组件，将会被渲染到 router-view 所在的位置 --&gt;
&lt;router-view&gt;&lt;/router-view&gt;</code></pre>
<p>4.定义路由组件</p>
<pre><code class="js">var User = {
    template: &#39;&lt;div&gt;User&lt;/div&gt;&#39;
}
var Register = {
    template: &#39;&lt;div&gt;Register&lt;/div&gt;&#39;
}</code></pre>
<p>5.配置路由规则并创建路由实例 </p>
<pre><code class="js">// 创建路由实例对象
var router = new VueRouter({
    // routes 是路由规则数组
    routes: [
        // 每个路由规则都是一个配置对象，其中至少包含 path 和 component 两个属性：
        // path 表示当前路由规则匹配的 hash 地址
        // component 表示当前路由规则对应要展示的组件
        {path:&#39;/user&#39;,component: User},
        {path:&#39;/register&#39;,component: Register}
    ]
})</code></pre>
<p> 6.把路由挂载到 Vue 根实例中 </p>
<pre><code class="js">new Vue({
    el: &#39;#app&#39;,
    // 为了能够让路由规则生效，必须把路由对象挂载到 vue 实例对象上
    router
});</code></pre>
<h4 id="路由重定向"><a href="#路由重定向" class="headerlink" title="路由重定向"></a>路由重定向</h4><p>路由重定向指的是：用户在访问地址 A 的时候，强制用户跳转到地址 C ，从而展示特定的组件页面； 通过路由规则的 redirect 属性，指定一个新的路由地址，可以很方便地设置路由的重定向</p>
<pre><code class="js">var router = new VueRouter({
    routes: [
        // 其中，path 表示需要被重定向的原地址，redirect 表示将要被重定向到的新地址
        {path:&#39;/&#39;, redirect: &#39;/user&#39;},
        {path:&#39;/user&#39;,component: User},
        {path:&#39;/register&#39;,component: Register}
    ]
})</code></pre>
<h4 id="vue-router-嵌套路由"><a href="#vue-router-嵌套路由" class="headerlink" title="vue-router 嵌套路由"></a>vue-router 嵌套路由</h4><p>嵌套路由功能分析</p>
<ul>
<li>点击父级路由链接显示模板内容</li>
<li>模板内容中又有子级路由链接</li>
<li>点击子级路由链接显示子级模板内容 </li>
</ul>
<p><img src="http://helloxx.cn/5.png" srcset="/myblog/img/loading.gif" alt=""></p>
<p>父路由组件模板 </p>
<ul>
<li>父级路由链接</li>
<li>父组件路由填充位 </li>
</ul>
<pre><code class="html">&lt;p&gt;
    &lt;router-link to=&quot;/user&quot;&gt;User&lt;/router-link&gt;
    &lt;router-link to=&quot;/register&quot;&gt;Register&lt;/router-link&gt;
&lt;/p&gt;
&lt;div&gt;
    &lt;!-- 控制组件的显示位置 --&gt;
    &lt;router-view&gt;&lt;/router-view&gt;
&lt;/div&gt;</code></pre>
<p> 子级路由模板 </p>
<ul>
<li>子级路由链接</li>
<li>子级路由填充位 </li>
</ul>
<pre><code class="js">const Register = {
    template: `&lt;div&gt;
                &lt;h1&gt;Register 组件&lt;/h1&gt;
                &lt;hr/&gt;
                &lt;router-link to=&quot;/register/tab1&quot;&gt;Tab1&lt;/router-link&gt;
                &lt;router-link to=&quot;/register/tab2&quot;&gt;Tab2&lt;/router-link&gt;
                &lt;!-- 子路由填充位置 --&gt;
                &lt;router-view/&gt;
                &lt;/div&gt;`
}


//子路由
const Tab1 = {
    template: &#39;&lt;h3&gt;tab1 子组件&lt;/h3&gt;&#39;
}

const Tab2 = {
    template: &#39;&lt;h3&gt;tab2 子组件&lt;/h3&gt;&#39;
}</code></pre>
<p> 嵌套路由配置</p>
<p> 父级路由通过children属性配置子级路由 </p>
<pre><code class="js">const router = new VueRouter({
    routes: [
        { path: &#39;/user&#39;, component: User },
        {
            path: &#39;/register&#39;,
            component: Register,
            // 通过 children 属性，为 /register 添加子路由规则
            children: [
                { path: &#39;/register/tab1&#39;, component: Tab1 },
                { path: &#39;/register/tab2&#39;, component: Tab2 }
            ]
        }
    ]
})</code></pre>
<h4 id="vue-router动态路由匹配"><a href="#vue-router动态路由匹配" class="headerlink" title="vue-router动态路由匹配"></a>vue-router动态路由匹配</h4><pre><code class="js">思考：
    &lt;!– 有如下 3 个路由链接 --&gt;
&lt;router-link to=&quot;/user/1&quot;&gt;User1&lt;/router-link&gt;
&lt;router-link to=&quot;/user/2&quot;&gt;User2&lt;/router-link&gt;
&lt;router-link to=&quot;/user/3&quot;&gt;User3&lt;/router-link&gt;
// 定义如下三个对应的路由规则，是否可行？？？   
{ path: &#39;/user/1&#39;, component: User }
{ path: &#39;/user/2&#39;, component: User }
{ path: &#39;/user/3&#39;, component: User }</code></pre>
<p> 动态匹配路由的基本用法 </p>
<pre><code class="js">// 通过动态路由参数的模式进行路由匹配
var router = new VueRouter({
    routes: [
        // 动态路径参数 以冒号开头
        { path: &#39;/user/:id&#39;, component: User }
    ]
})


const User = {
    // 路由组件中通过$route.params获取路由参数
    template: &#39;&lt;div&gt;User {{ $route.params.id }}&lt;/div&gt;&#39;
}</code></pre>
<p> 路由组件传递参数 </p>
<p> <code>$route</code>与对应路由形成高度耦合，不够灵活，所以可以使用props将组件和路由解耦 </p>
<pre><code class="js">//props的值为布尔类型
const router = new VueRouter({
    routes: [
        // 如果 props 被设置为 true，route.params 将会被设置为组件属性
        { path: &#39;/user/:id&#39;, component: User, props: true }
    ]
})
const User = {
    props: [&#39;id&#39;], // 使用 props 接收路由参数
    template: &#39;&lt;div&gt;用户ID：{{ id }}&lt;/div&gt;&#39; // 使用路由参数
}

--------------------
//props的值为对象类型
const router = new VueRouter({
    routes: [
        // 如果 props 是一个对象，它会被按原样设置为组件属性
        { path: &#39;/user/:id&#39;, component: User, props: { uname: &#39;lisi&#39;, age: 12 }}
    ]
})
const User = {
    props: [&#39;uname&#39;, &#39;age&#39;],
    template: ‘&lt;div&gt;用户信息：{{ uname + '---' + age}}&lt;/div&gt;&#39;
}

//-------------------
//props的值为函数类型
const router = new VueRouter({
    routes: [
        // 如果 props 是一个函数，则这个函数接收 route 对象为自己的形参
        { path: &#39;/user/:id&#39;,
         component: User,
         props: route =&gt; ({ uname: &#39;zs&#39;, age: 20, id: route.params.id })}
    ]
})
const User = {
    props: [&#39;uname&#39;, &#39;age&#39;, &#39;id&#39;],
    template: ‘&lt;div&gt;用户信息：{{ uname + '---' + age + '---' + id}}&lt;/div&gt;&#39;
}
</code></pre>
<h4 id="vue-router命名路由"><a href="#vue-router命名路由" class="headerlink" title="vue-router命名路由"></a>vue-router命名路由</h4><p> 为了更加方便的表示路由的路径，可以给路由规则起一个别名，即为“命名路由”。 </p>
<pre><code class="js">const router = new VueRouter({
    routes: [
        {
            path: &#39;/user/:id&#39;,
            name: &#39;user&#39;,
            component: User
        }
    ]
})


&lt;router-link :to=&quot;{ name: &#39;user&#39;, params: { id: 123 }}&quot;&gt;User&lt;/router-link&gt;
router.push({ name: &#39;user&#39;, params: { id: 123 }})</code></pre>
<h4 id="vue-router编程式导航"><a href="#vue-router编程式导航" class="headerlink" title="vue-router编程式导航"></a>vue-router编程式导航</h4><p> 页面导航的两种方式 </p>
<ul>
<li><p>声明式导航：通过点击链接实现导航的方式，叫做声明式导航 例如：普通网页中的  链接 或 vue 中的</p>
</li>
<li><p>编程式导航：通过调用JavaScript形式的API实现导航的方式，叫做编程式导航 例如：普通网页中的 location.href  </p>
<p>编程式导航基本用法 </p>
<p>常用的编程式导航 API 如下：</p>
</li>
<li><p><code>this.$router.push(&#39;hash地址&#39;)</code></p>
</li>
<li><p><code>this.$router.go(n)</code></p>
</li>
</ul>
<pre><code class="js">const User = {
    template: &#39;&lt;div&gt;&lt;button @click=&quot;goRegister&quot;&gt;跳转到注册页面&lt;/button&gt;&lt;/div&gt;&#39;,
    methods: {
        goRegister: function(){
            // 用编程的方式控制路由跳转
            this.$router.push(&#39;/register&#39;);
        }
    }
}

const Register = {
    template:`&lt;div&gt;
        &lt;h1&gt;Register组件&lt;/h1&gt;
        &lt;button @click=&quot;goBack&quot;&gt;后退&lt;/button&gt;
        &lt;/div&gt;`,
    methods:{
        goBack(){
            //-1表示后退
            this.$router.go(-1)
        }
    }
}</code></pre>
<p> router.push() 方法的参数规则 </p>
<pre><code class="js">// 字符串(路径名称)
router.push(&#39;/home&#39;)
// 对象
router.push({ path: &#39;/home&#39; })
// 命名的路由(传递参数)
router.push({ name: &#39;/user&#39;, params: { userId: 123 }})
// 带查询参数，变成 /register?uname=lisi
router.push({ path: &#39;/register&#39;, query: { uname: &#39;lisi&#39; }})</code></pre>
<h2 id="关于地址栏的-号"><a href="#关于地址栏的-号" class="headerlink" title="关于地址栏的#号"></a>关于地址栏的#号</h2><p>地址栏中，经常出现#，为hash模式<br>hash模式：地址栏包含#符号，#以后的不被后台获取，可以减少浏览器到后台的访问次数</p>
<p>history模式：具有对url历史记录进行修改的功能</p>
<p>在微信支付、分享url作为参数传递时，#不能满足需求，因为不能出现特殊符号</p>
<p>history需要后台配合，处理404的问题，因为访问不存在的页面会出现404</p>
<p>在路由文件中，追加</p>
<pre><code>export default new Router({ 
mode:&#39;history&#39;)}</code></pre><h2 id="模块化的分类"><a href="#模块化的分类" class="headerlink" title="模块化的分类"></a>模块化的分类</h2><p>传统开发模式的主要问题有 命名冲突和文件依赖，通过模块化解决上述问题</p>
<p>模块化就是把单独的一个功能封装到一个模块（文件）中，模块之间相互隔离，但是可以通过特定的接口公开内部成员，也可以依赖别的模块</p>
<p>模块化开发的好处：方便代码的重用，从而提升开发效率，并且方便后期的维护</p>
<h4 id="A-浏览器端的模块化（落伍）"><a href="#A-浏览器端的模块化（落伍）" class="headerlink" title="A.浏览器端的模块化（落伍）"></a>A.浏览器端的模块化（落伍）</h4><p>​        1).AMD(Asynchronous Module Definition,异步模块定义)<br>​        代表产品为：Require.js</p>
<p>​        2).CMD(Common Module Definition,通用模块定义)<br>​        代表产品为：Sea.js</p>
<h4 id="B-服务器端的模块化"><a href="#B-服务器端的模块化" class="headerlink" title="B.服务器端的模块化"></a>B.服务器端的模块化</h4><p>​        服务器端的模块化规范是使用CommonJS规范：<br>​        1).使用require引入其他模块或者包<br>​        2).使用exports或者module.exports导出模块成员<br>​        3).一个文件就是一个模块，都拥有独立的作用域</p>
<h4 id="C-ES6模块化"><a href="#C-ES6模块化" class="headerlink" title="C.ES6模块化"></a>C.ES6模块化</h4><p>​        ES6模块化规范中定义：<br>​            1).每一个js文件都是独立的模块<br>​            2).导入模块成员使用import关键字<br>​            3).暴露模块成员使用export关键字</p>
<p>小结：推荐使用ES6模块化，因为AMD，CMD局限使用与浏览器端，而CommonJS在服务器端使用。<br>      ES6模块化是浏览器端和服务器端通用的规范.</p>
<h2 id="在NodeJS中安装babel"><a href="#在NodeJS中安装babel" class="headerlink" title="在NodeJS中安装babel"></a>在NodeJS中安装babel</h2><h4 id="A-安装babel"><a href="#A-安装babel" class="headerlink" title="A.安装babel"></a>A.安装babel</h4><p>​    打开终端，输入命令：</p>
<pre><code>npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/node</code></pre><p>​    安装完毕之后，再次输入命令安装：</p>
<pre><code>npm install --save @babel/polyfill</code></pre><h4 id="B-创建babel-config-js"><a href="#B-创建babel-config-js" class="headerlink" title="B.创建babel.config.js"></a>B.创建babel.config.js</h4><p>​    在项目目录中创建babel.config.js文件。<br>​    编辑js文件中的代码如下：   </p>
<pre><code class="js">const presets = [
    [&quot;@babel/env&quot;,{
        targets:{
            edge:&quot;17&quot;,
            firefox:&quot;60&quot;,
            chrome:&quot;67&quot;,
            safari:&quot;11.1&quot;
        }
    }]
]
//暴露
module.exports = { presets }</code></pre>
<h4 id="C-创建index-js文件"><a href="#C-创建index-js文件" class="headerlink" title="C.创建index.js文件"></a>C.创建index.js文件</h4><p>​    在项目目录中创建index.js文件作为入口文件<br>​    在index.js中输入需要执行的js代码，例如：<br>​        console.log(“ok”);</p>
<h4 id="D-使用npx执行文件"><a href="#D-使用npx执行文件" class="headerlink" title="D.使用npx执行文件"></a>D.使用npx执行文件</h4><p>​    打开终端，输入命令：</p>
<pre><code>npx babel-node ./index.js
//表示配置成功</code></pre><h2 id="ES6模块化-设置默认导入-导出"><a href="#ES6模块化-设置默认导入-导出" class="headerlink" title="ES6模块化-设置默认导入/导出"></a>ES6模块化-设置默认导入/导出</h2><h4 id="A-默认导出"><a href="#A-默认导出" class="headerlink" title="A.默认导出"></a>A.默认导出</h4><pre><code class="js">//默认导出语法 export default 默认导出的成员
let num = 100;
export default{
    num
}</code></pre>
<h4 id="B-默认导入"><a href="#B-默认导入" class="headerlink" title="B.默认导入"></a>B.默认导入</h4><pre><code>import 接收名称 from &quot;模块标识符&quot;，如下：
import test from &quot;./test.js&quot;</code></pre><p>注意：在一个模块中，只允许使用export default向外默认暴露一次成员，千万不要写多个export default。<br>如果在一个模块中没有向外暴露成员，其他模块引入该模块时将会得到一个空对象 </p>
<h2 id="设置按需导入-导出"><a href="#设置按需导入-导出" class="headerlink" title="设置按需导入/导出"></a>设置按需导入/导出</h2><h4 id="A-按需导出"><a href="#A-按需导出" class="headerlink" title="A.按需导出"></a>A.按需导出</h4><pre><code class="js">export let num = 998;
export let myName = &quot;jack&quot;;
export function fn = function(){ console.log(&quot;fn&quot;) }</code></pre>
<h4 id="B-按需导入"><a href="#B-按需导入" class="headerlink" title="B.按需导入"></a>B.按需导入</h4><pre><code class="js">import { num,fn as printFn ,myName } from &quot;./test.js&quot;
//同时导入默认导出的成员以及按需导入的成员
import test,{ num,fn as printFn ,myName } from &quot;./test.js&quot;</code></pre>
<p>注意：一个模块中既可以按需导入也可以默认导入，一个模块中既可以按需导出也可以默认导出</p>
<h2 id="直接导入并执行代码"><a href="#直接导入并执行代码" class="headerlink" title="直接导入并执行代码"></a>直接导入并执行代码</h2><p>有时候，我们只想单纯执行某个模块中的代码，并不需要得到模块中向外暴露的成员，此时，可以直接导入并执行模块代码。</p>
<pre><code>import &quot;./test2.js&quot;;</code></pre><h2 id="webpack的概念"><a href="#webpack的概念" class="headerlink" title="webpack的概念"></a>webpack的概念</h2><p>webpack是一个流行的前端项目构建工具，可以解决目前web开发的困境。<br>webpack提供了模块化支持，代码压缩混淆，解决js兼容问题，性能优化等特性，提高了开发效率和项目的可维护性</p>
<p><img src="http://helloxx.cn/7.png" srcset="/myblog/img/loading.gif" alt=""></p>
<h2 id="7-webpack的基本使用"><a href="#7-webpack的基本使用" class="headerlink" title="7.webpack的基本使用"></a>7.webpack的基本使用</h2><p>1.创建项目目录并初始化</p>
<p>​    创建项目，并打开项目所在目录的终端，输入命令：</p>
<pre><code>npm init -y</code></pre><p>2.创建首页及js文件</p>
<p>​    在项目目录中创建index.html页面，并初始化页面结构：在页面中摆放一个ul，ul里面放置几个li<br>​    在项目目录中创建js文件夹，并在文件夹中创建index.js文件</p>
<p>3.安装jQuery</p>
<p>​    打开项目目录终端，输入命令:    </p>
<pre><code>npm install jQuery -S</code></pre><p>4.导入jQuery</p>
<p>​    打开index.js文件，编写代码导入jQuery并实现功能：</p>
<pre><code class="js">import $ from &quot;jquery&quot;;
$(function(){
    $(&quot;li:odd&quot;).css(&quot;background&quot;,&quot;cyan&quot;);
    $(&quot;li:odd&quot;).css(&quot;background&quot;,&quot;pink&quot;);
})</code></pre>
<p>注意：此时项目运行会有错误，因为<code>import $ from &quot;jquery&quot;;</code>这句代码属于ES6的新语法代码，在浏览器中可能会存在兼容性问题<br>所以我们需要webpack来帮助我们解决这个问题。</p>
<p>5.安装webpack</p>
<p>​    1).打开项目目录终端，输入命令: </p>
<pre><code>npm install webpack webpack-cli -D</code></pre><p>​    2).然后在项目根目录中，创建一个 webpack.config.js 的配置文件用来配置webpack<br>​    在 webpack.config.js 文件中编写代码进行webpack配置，如下：​    </p>
<pre><code class="js">module.exports = {
    mode:&quot;development&quot;//可以设置为development(开发模式)，production(发布模式)
}</code></pre>
<p>​    补充：mode设置的是项目的编译模式。<br>​    如果设置为development则表示项目处于开发阶段，不会进行压缩和混淆，打包速度会快一些<br>​    如果设置为production则表示项目处于上线发布阶段，会进行压缩和混淆，打包速度会慢一些</p>
<p>​    3).修改项目中的package.json文件添加运行脚本dev，如下：​   </p>
<pre><code> &quot;scripts&quot;:{
       &quot;dev&quot;:&quot;webpack&quot;
    }
</code></pre><p>​    注意：scripts节点下的脚本，可以通过 npm run 运行，如：<br>​    运行终端命令：npm run dev<br>​    将会启动webpack进行项目打包</p>
<p>​    4).运行dev命令进行项目打包，并在页面中引入项目打包生成的js文件<br>​    打开项目目录终端，输入命令:<br>​    npm run dev<br>​    等待webpack打包完毕之后，找到默认的dist路径中生成的main.js文件，将其引入到html页面中。<br>​    浏览页面查看效果。</p>
<h2 id="8-设置webpack的打包入口-出口"><a href="#8-设置webpack的打包入口-出口" class="headerlink" title="8.设置webpack的打包入口/出口"></a>8.设置webpack的打包入口/出口</h2><p>​    在webpack 4.x中，默认会将src/index.js 作为默认的打包入口js文件，默认会将dist/main.js 作为默认的打包输出js文件<br>​    如果不想使用默认的入口/出口js文件，我们可以通过改变 webpack.config.js 来设置入口/出口的js文件，如下：​   </p>
<pre><code class="js">const path = require(&quot;path&quot;);//导出node.js中专门操作路径的模块
module.exports = {
    mode:&quot;development&quot;,
    //设置入口文件路径
    entry: path.join(__dirname,&quot;./src/xx.js&quot;), //打包入口文件的路径
    //设置出口文件
    output:{
        //设置输出文件存放路径
        path:path.join(__dirname,&quot;./dist&quot;),
        //设置输出文件名
        filename:&quot;res.js&quot;
    }
}
</code></pre>
<h2 id="9-设置webpack的自动打包"><a href="#9-设置webpack的自动打包" class="headerlink" title="9.设置webpack的自动打包"></a>9.设置webpack的自动打包</h2><p>默认情况下，我们更改入口js文件的代码，需要重新运行命令打包webpack，才能生成出口的js文件<br>那么每次都要重新执行命令打包，这是一个非常繁琐的事情，那么，自动打包可以解决这样繁琐的操作。</p>
<p>实现自动打包功能的步骤如下：</p>
<p>1.安装自动打包功能的包:webpack-dev-server​</p>
<pre><code>npm install webpack-dev-server -D
</code></pre><p>2.修改package.json中的dev指令如下：</p>
<pre><code class="json">&quot;scripts&quot;:{
    &quot;dev&quot;:&quot;webpack-dev-server&quot;
}
</code></pre>
<p>3.将引入的js文件路径更改为：<code>&lt;script src=&quot;/bundle.js&quot;&gt;&lt;/script&gt;</code></p>
<p>4.运行npm run dev，进行打包</p>
<p>5.打开网址查看效果：<code>http://localhost:8080</code></p>
<pre><code>注意：webpack-dev-server自动打包的输出文件，默认放到了服务器的根目录中.存放到内存中</code></pre><p>补充：<br>在自动打包完毕之后，默认打开服务器网页，实现方式就是打开package.json文件，修改dev命令：</p>
<pre><code>//--open 打包完成后自动打开浏览器页面
//--host 配置IP地址
//--port 配置端口
&quot;scripts&quot;:{&quot;dev&quot;: &quot;webpack-dev-server --open --host 127.0.0.1 --port 9999&quot;}
</code></pre><h2 id="10-配置html-webpack-plugin"><a href="#10-配置html-webpack-plugin" class="headerlink" title="10.配置html-webpack-plugin"></a>10.配置html-webpack-plugin</h2><p>使用html-webpack-plugin 可以生成一个预览页面。<br>因为当我们访问默认的<code>http://localhost:8080/</code>的时候，看到的是一些文件和文件夹，想要查看我们的页面还需要点击文件夹点击文件才能查看，那么我们希望默认就能看到一个页面，而不是看到文件夹或者目录。</p>
<p>实现默认预览页面功能的步骤如下：</p>
<p>1.安装默认预览功 能的包:html-webpack-plugin</p>
<pre><code>npm install html-webpack-plugin -D
</code></pre><p>2.修改webpack.config.js文件，如下：​            </p>
<pre><code class="js">//导入包
const HtmlWebpackPlugin = require(&quot;html-webpack-plugin&quot;);
//创建对象
const htmlPlugin = new HtmlWebpackPlugin({
    //设置生成预览页面的模板文件
    template:&quot;./src/index.html&quot;,
    //设置生成的预览页面名称
    filename:&quot;index.html&quot;
})
</code></pre>
<p>3.继续修改webpack.config.js文件，添加plugins信息:            </p>
<pre><code class="js">module.exports = {
    ......
    plugins:[ htmlPlugin ]
}
</code></pre>
<h2 id="11-webpack中的加载器"><a href="#11-webpack中的加载器" class="headerlink" title="11.webpack中的加载器"></a>11.webpack中的加载器</h2><p>通过loader打包非js模块：默认情况下, webpack只能打包js文件，如果想要打包非js文件，需要调用loader加载器才能打包</p>
<p><img src="http://helloxx.cn/6.png" srcset="/myblog/img/loading.gif" alt=""></p>
<p>loader加载器包含：</p>
<ol>
<li>less-loader</li>
<li>sass-loader</li>
<li>url-loader:打包处理css中与url路径有关的文件</li>
<li>babel-loader:处理高级js语法的加载器</li>
<li>postcss-loader</li>
<li>css-loader,style-loader</li>
</ol>
<p>注意：指定多个loader时的顺序是固定的，而调用loader的顺序是从后向前进行调用</p>
<h4 id="1-安装style-loader-css-loader来处理css样式文件"><a href="#1-安装style-loader-css-loader来处理css样式文件" class="headerlink" title="1.安装style-loader,css-loader来处理css样式文件"></a>1.安装style-loader,css-loader来处理css样式文件</h4><p>1).安装包</p>
<pre><code>npm install style-loader css-loader -D
</code></pre><p>2).配置规则：更改webpack.config.js的module中的rules数组   </p>
<pre><code class="js">module.exports = {
    ......
    plugins:[ htmlPlugin ],
    module : {
        rules:[
            {
                //test设置需要匹配的文件类型，支持正则
                test:/\.css$/,
                //use表示该文件类型需要调用的loader
                use:[&#39;style-loader&#39;,&#39;css-loader&#39;]
                //指定多个loader时的顺序是固定的，而调用loader的顺序是从后向前进行调用
            }
        ]
    }
}
</code></pre>
<p>​    </p>
<h4 id="2-安装less-less-loader处理less文件"><a href="#2-安装less-less-loader处理less文件" class="headerlink" title="2.安装less,less-loader处理less文件"></a>2.安装less,less-loader处理less文件</h4><p>​    1).安装包</p>
<pre><code>npm install less-loader less -D
</code></pre><p>​    2).配置规则：更改webpack.config.js的module中的rules数组</p>
<pre><code class="js">module.exports = {
    ......
    plugins:[ htmlPlugin ],
    module : {
        rules:[
            {
                //test设置需要匹配的文件类型，支持正则
                test:/\.css$/,
                //use表示该文件类型需要调用的loader
                use:[&#39;style-loader&#39;,&#39;css-loader&#39;]
            },
            {
                test:/\.less$/,
                use:[&#39;style-loader&#39;,&#39;css-loader&#39;,&#39;less-loader&#39;]
            }
        ]
    }
}
</code></pre>
<h4 id="3-安装sass-loader-node-sass处理sass文件"><a href="#3-安装sass-loader-node-sass处理sass文件" class="headerlink" title="3.安装sass-loader,node-sass处理sass文件"></a>3.安装sass-loader,node-sass处理sass文件</h4><p>1).安装包</p>
<pre><code>npm install sass-loader node-sass -D
</code></pre><p>2).配置规则：更改webpack.config.js的module中的rules数组</p>
<pre><code class="js">module.exports = {
    ......
    plugins:[ htmlPlugin ],
    module : {
        rules:[
            {
                //test设置需要匹配的文件类型，支持正则
                test:/\.css$/,
                //use表示该文件类型需要调用的loader
                use:[&#39;style-loader&#39;,&#39;css-loader&#39;]
            },
            {
                test:/\.less$/,
                use:[&#39;style-loader&#39;,&#39;css-loader&#39;,&#39;less-loader&#39;]
            },
            {
                test:/\.scss$/,
                use:[&#39;style-loader&#39;,&#39;css-loader&#39;,&#39;sass-loader&#39;]
            }
        ]
    }
}
</code></pre>
<p>​    补充：安装sass-loader失败时，大部分情况是因为网络原因，详情参考：<br><code>​https://segmentfault.com/a/1190000010984731?utm_source=tag-newest</code></p>
<h4 id="4-安装post-css自动添加css的兼容性前缀（-ie-webkit-）"><a href="#4-安装post-css自动添加css的兼容性前缀（-ie-webkit-）" class="headerlink" title="4.安装post-css自动添加css的兼容性前缀（-ie-,-webkit-）"></a>4.安装post-css自动添加css的兼容性前缀（-ie-,-webkit-）</h4><p>1).安装包</p>
<pre><code>npm install postcss-loader autoprefixer -D
</code></pre><p>2).在项目根目录创建并配置postcss.config.js文件</p>
<pre><code class="js">const autoprefixer = require(&quot;autoprefixer&quot;);//导入自动添加前缀的插件
module.exports = {
    plugins:[ autoprefixer ]//挂载插件
}
</code></pre>
<p>3).配置规则：更改webpack.config.js的module中的rules数组</p>
<pre><code class="js">module.exports = {
    ......
    plugins:[ htmlPlugin ],
    module : {
        rules:[
            {
                //test设置需要匹配的文件类型，支持正则
                test:/\.css$/,
                //use表示该文件类型需要调用的loader
                use:[&#39;style-loader&#39;,&#39;css-loader&#39;,&#39;postcss-loader&#39;]
            },
            {
                test:/\.less$/,
                use:[&#39;style-loader&#39;,&#39;css-loader&#39;,&#39;less-loader&#39;]
            },
            {
                test:/\.scss$/,
                use:[&#39;style-loader&#39;,&#39;css-loader&#39;,&#39;sass-loader&#39;]
            }
        ]
    }
}
</code></pre>
<h4 id="5-打包样式表中的图片以及字体文件"><a href="#5-打包样式表中的图片以及字体文件" class="headerlink" title="5.打包样式表中的图片以及字体文件"></a>5.打包样式表中的图片以及字体文件</h4><p>在样式表css中有时候会设置背景图片和设置字体文件，一样需要loader进行处理</p>
<p>使用url-loader和file-loader来处理打包图片文件以及字体文件</p>
<p>1).安装包</p>
<pre><code>npm install url-loader file-loader -D
</code></pre><p>2).配置规则：更改webpack.config.js的module中的rules数组</p>
<pre><code class="js">module.exports = {
    ......
    plugins:[ htmlPlugin ],
    module : {
        rules:[
            {
                //test设置需要匹配的文件类型，支持正则
                test:/\.css$/,
                //use表示该文件类型需要调用的loader
                use:[&#39;style-loader&#39;,&#39;css-loader&#39;]
            },
            {
                test:/\.less$/,
                use:[&#39;style-loader&#39;,&#39;css-loader&#39;,&#39;less-loader&#39;]
            },
            {
                test:/\.scss$/,
                use:[&#39;style-loader&#39;,&#39;css-loader&#39;,&#39;sass-loader&#39;]
            },{
                test:/\.jpg|png|gif|bmp|ttf|eot|svg|woff|woff2$/,
        //limit 用来指定图片的大小，单位是字节(byte),只有小于 limit 大小的图片，才会被转为 base64 图片
                use:&quot;url-loader?limit=16940&quot;
            }
        ]
    }
}
</code></pre>
<h4 id="6-打包js文件中的高级语法：在编写js的时候，有时候我们会使用高版本的js语法"><a href="#6-打包js文件中的高级语法：在编写js的时候，有时候我们会使用高版本的js语法" class="headerlink" title="6.打包js文件中的高级语法：在编写js的时候，有时候我们会使用高版本的js语法"></a>6.打包js文件中的高级语法：在编写js的时候，有时候我们会使用高版本的js语法</h4><p>有可能这些高版本的语法不被兼容，我们需要将之打包为兼容性的js代码</p>
<p>我们需要安装babel系列的包</p>
<p>A.安装babel转换器</p>
<pre><code>npm install babel-loader @babel/core @babel/runtime -D
</code></pre><p>B.安装babel语法插件包</p>
<pre><code>npm install @babel/preset-env @babel/plugin-transform-runtime @babel/plugin-proposal-class-properties -D
</code></pre><p>C.在项目根目录创建并配置babel.config.js文件</p>
<pre><code class="js">module.exports = {
    presets:[&quot;@babel/preset-env&quot;],
    plugins:[ &quot;@babel/plugin-transform-runtime&quot;, &quot;@babel/plugin-proposal-class-properties&quot; ]
}
</code></pre>
<p>D.配置规则：更改webpack.config.js的module中的rules数组</p>
<pre><code class="js">module.exports = {
    ......
    plugins:[ htmlPlugin ],
    module : {
        rules:[
            {
                //test设置需要匹配的文件类型，支持正则
                test:/\.css$/,
                //use表示该文件类型需要调用的loader
                use:[&#39;style-loader&#39;,&#39;css-loader&#39;]
            },
            {
                test:/\.less$/,
                use:[&#39;style-loader&#39;,&#39;css-loader&#39;,&#39;less-loader&#39;]
            },
            {
                test:/\.scss$/,
                use:[&#39;style-loader&#39;,&#39;css-loader&#39;,&#39;sass-loader&#39;]
            },{
                test:/\.jpg|png|gif|bmp|ttf|eot|svg|woff|woff2$/,
                //limit用来设置字节数，只有小于limit值的图片，才会转换
                //为base64图片
                use:&quot;url-loader?limit=16940&quot;
            },{
                test:/\.js$/,
                use:&quot;babel-loader&quot;,
                //exclude为排除项，意思是不要处理node_modules中的js文件
                exclude:/node_modules/
            }
        ]
    }
}
</code></pre>
<h2 id="12-Vue单文件组件"><a href="#12-Vue单文件组件" class="headerlink" title="12.Vue单文件组件"></a>12.Vue单文件组件</h2><p>传统Vue组件的缺陷：</p>
<ol>
<li>全局定义的组件必须保证组件的名称不重复</li>
<li>字符串模板缺乏语法高亮，在 HTML 有多行的时候，需要用到丑陋的 \ </li>
<li>不支持 CSS 意味着当 HTML 和 JavaScript 组件化时，CSS 明显被遗漏</li>
<li>没有构建步骤限制，只能使用 HTML 和 ES5 JavaScript, 而不能使用预处理器（如：Babel） </li>
</ol>
<p>解决方案：<br>使用Vue单文件组件，每个单文件组件的后缀名都是.vue<br>每一个Vue单文件组件都由三部分组成<br>1).template组件组成的模板区域<br>2).script组成的业务逻辑区域<br>3).style样式区域</p>
<p>代码如下：</p>
<pre><code class="html">&lt;template&gt;
    &lt;!-- 这里用于定义Vue组件的模板内容 --&gt;
&lt;/template&gt;
&lt;script&gt;
    // 这里用于定义Vue组件的业务逻辑
    export default {
        data: () { return {} }, // 私有数据
            methods: {} // 处理函数
    // ... 其它业务逻辑
    }
&lt;/script&gt;
&lt;style scoped&gt; //scoped 防止样式冲突
    /* 这里用于定义组件的样式 */
&lt;/style&gt;
</code></pre>
<p>补充：安装Vetur插件可以使得.vue文件中的代码高亮</p>
<p>配置.vue文件的加载器</p>
<p>A.安装vue组件的加载器</p>
<pre><code>npm install vue-loader vue-template-compiler -D
</code></pre><p>B.配置规则：更改webpack.config.js的module中的rules数组</p>
<pre><code class="js">const VueLoaderPlugin = require(&quot;vue-loader/lib/plugin&quot;);
const vuePlugin = new VueLoaderPlugin();
module.exports = {
    ......
    plugins:[ htmlPlugin, vuePlugin  ],
    module : {
        rules:[
            ...//其他规则
            { 
                test:/\.vue$/,
                loader:&quot;vue-loader&quot;, 
            }
        ]
    }
}
</code></pre>
<h2 id="13-在webpack中使用vue"><a href="#13-在webpack中使用vue" class="headerlink" title="13.在webpack中使用vue"></a>13.在webpack中使用vue</h2><p>上一节我们安装处理了vue单文件组件的加载器，想要让vue单文件组件能够使用，我们必须要安装vue<br>并使用vue来引用vue单文件组件。<br>A.安装Vue</p>
<p>​    npm install vue -S</p>
<p>B.导入app根组件</p>
<p>import app from ‘./app.vue’</p>
<p>C.在index.js中引入vue：import Vue from “vue”</p>
<p>D.创建Vue实例对象并指定el，最后使用render函数渲染单文件组件  </p>
<pre><code class="js">const vm = new Vue({
    el:&quot;#first&quot;,
    render:h=&gt;h(app)
})
</code></pre>
<h2 id="14-使用webpack打包发布项目"><a href="#14-使用webpack打包发布项目" class="headerlink" title="14.使用webpack打包发布项目"></a>14.使用webpack打包发布项目</h2><p>在项目上线之前，我们需要将整个项目打包并发布。<br>A.配置package.json</p>
<pre><code class="JSON">&quot;scripts&quot;:{
    &quot;dev&quot;:&quot;webpack-dev-server&quot;,
    &quot;build&quot;:&quot;webpack -p&quot; //用于打包的命令
}
</code></pre>
<p>B.在项目打包之前，可以将dist目录删除，生成全新的dist目录</p>
<p>C.运行 npm run build</p>
<h2 id="15-Vue脚手架"><a href="#15-Vue脚手架" class="headerlink" title="15.Vue脚手架"></a>15.Vue脚手架</h2><p>Vue脚手架可以快速生成Vue项目基础的架构。<br>A.安装3.x版本的Vue脚手架：</p>
<p>​    npm install -g @vue/cli</p>
<p>B.基于3.x版本的脚手架创建Vue项目：</p>
<p>​    1).使用命令创建Vue项目<br>​        命令：vue create my-project<br>​        选择Manually select features(选择特性以创建项目)<br>​        勾选特性可以用空格进行勾选。<br>​        是否选用历史模式的路由：n<br>​        ESLint选择：ESLint + Standard config<br>​        何时进行ESLint语法校验：Lint on save<br>​        babel，postcss等配置文件如何放置：In dedicated config files(单独使用文件进行配置)<br>​        是否保存为模板：n<br>​        使用哪个工具安装包：npm</p>
<p>​    2).基于ui界面创建Vue项目<br>​        命令：vue ui<br>​        在自动打开的创建项目网页中配置项目信息。</p>
<p>​    3).基于2.x的旧模板，创建Vue项目<br>​        npm install -g @vue/cli-init<br>​        vue init webpack my-project</p>
<p>C.分析Vue脚手架生成的项目结构<br>    node_modules:依赖包目录<br>    public：静态资源目录<br>    src：源码目录<br>    src/assets:资源目录<br>    src/components：组件目录<br>    src/views:视图组件目录<br>    src/App.vue:根组件<br>    src/main.js:入口js<br>    src/router.js:路由js<br>    babel.config.js:babel配置文件<br>    .eslintrc.js:ESlint代码风格管理工具</p>
<h3 id="Vue-Cli2-x"><a href="#Vue-Cli2-x" class="headerlink" title="Vue Cli2.x"></a>Vue Cli2.x</h3><p>2.x安装</p>
<p>nmp 下 -g 表示全局安装</p>
<p>npm root -g 查看全局安装的文件夹位置</p>
<p>npm config set registry <a href="http://registry.npm.taobao.org" target="_blank" rel="noopener">http://registry.npm.taobao.org</a>  //更换为淘宝的镜像服务器</p>
<p>-S  或者 –save 安装包信息将加入到dependencies (生产阶段的依赖)</p>
<p>-D 或者 –save-dev安装包信息将加入到devDependencies( 开发阶段的依赖)</p>
<p>i 是install 的缩写, uni 是uninstall 的缩写</p>
<p>npm install -g vue-cli   //安装vue-cli2</p>
<p>npm uninstall -g vue-cli  // 卸载vue-cli</p>
<p><strong>创建 vue-cli项目</strong></p>
<p>vue init webpack projectName</p>
<p><strong>创建cli 过程中部分中的配置内容</strong></p>
<blockquote>
<p>Install vue-router //官方路由</p>
<p>Use ESlint to lint your code //ESlint代码风格管理工具</p>
</blockquote>
<p>进入项目目录</p>
<p>npm run dev //启动项目</p>
<h3 id="导入vue-cli项目"><a href="#导入vue-cli项目" class="headerlink" title="导入vue-cli项目"></a>导入vue-cli项目</h3><p>进入项目目录，运行 npm install 安装依赖</p>
<p>npm run dev //启动项目</p>
<h2 id="16-Vue脚手架的自定义配置"><a href="#16-Vue脚手架的自定义配置" class="headerlink" title="16.Vue脚手架的自定义配置"></a>16.Vue脚手架的自定义配置</h2><p>​    A.通过 package.json 进行配置 [不推荐使用]<br>​        “vue”:{<br>​            “devServer”:{<br>​                “port”:”9990”,<br>​                “open”:true<br>​            }<br>​        }<br>​    B.通过单独的配置文件进行配置，创建vue.config.js<br>​        module.exports = {<br>​            devServer:{<br>​                port:8888,<br>​                open:true<br>​            }<br>​        }</p>
<h2 id="17-Element-UI的基本使用"><a href="#17-Element-UI的基本使用" class="headerlink" title="17.Element-UI的基本使用"></a>17.Element-UI的基本使用</h2><p>Element-UI:一套基于2.0的桌面端组件库<br>官网地址：<a href="http://element-cn.eleme.io/#/zh-CN" target="_blank" rel="noopener">http://element-cn.eleme.io/#/zh-CN</a><br>A.安装：<br>    npm install element-ui -S<br>B.导入使用：</p>
<pre><code>import ElementUI from &quot;element-ui&quot;; //导入组件库
import &quot;element-ui/lib/theme-chalk/index.css&quot;; //导入组件相关样式
Vue.use(ElementUI) //配置vue插件
</code></pre><p>基于图形化界面自动安装</p>
<ol>
<li>运行 vue ui 命令，打开图形化界面</li>
<li>通过 Vue 项目管理器，进入具体的项目配置面板 </li>
<li>点击 插件 -&gt; 添加插件，进入插件查询面板</li>
<li>搜索 vue-cli-plugin-element 并安装</li>
<li>配置插件，实现按需导入，从而减少打包后项目的体积 </li>
</ol>

            </div>
            <hr>
            <div>
              <p>
                
                
              </p>
              
                <p class="note note-warning">本博客所有文章除特别声明外，均采用 <a href="https://zh.wikipedia.org/wiki/Wikipedia:CC_BY-SA_3.0%E5%8D%8F%E8%AE%AE%E6%96%87%E6%9C%AC" target="_blank" rel="nofollow noopener noopener">CC BY-SA 3.0协议</a> 。转载请注明出处！</p>
              
              
                <div class="post-prevnext row">
                  <div class="post-prev col-6">
                    
                    
                      <a href="/myblog/2019/05/05/%E5%89%8D%E7%AB%AF%E9%9D%A2%E8%AF%95%E5%B8%B8%E7%94%A8%E7%9F%A5%E8%AF%86%E7%82%B9/">
                        <i class="fa fa-chevron-left"></i>
                        <span class="hidden-mobile">前端面试</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </div>
                  <div class="post-next col-6">
                    
                    
                      <a href="/myblog/2019/04/15/JavaScript%E8%BF%9B%E9%98%B6%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1ES6%E7%AC%94%E8%AE%B0/">
                        <span class="hidden-mobile">JavaScript高级&ES6 学习笔记</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="fa fa-chevron-right"></i>
                      </a>
                    
                  </div>
                </div>
              
            </div>

              
          </div>
        </div>
      </div>
    </div>
    
      <div class="d-none d-lg-block col-lg-2 toc-container" id="toc-ctn">
        <div id="toc-start"></div>
<div id="toc">
  <p class="h5"><i class="far fa-list-alt"></i>&nbsp;目录</p>
  <div id="tocbot"></div>
</div>

      </div>
    
  </div>
</div>

<!-- Custom -->


    
  </main>

  
    <a class="z-depth-1" id="scroll-top-button" href="#" role="button">
      <i class="fa fa-chevron-up scroll-top-arrow" aria-hidden="true"></i>
    </a>
  

  
    <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v"
                 for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>
  

  

  

  <footer class="mt-5">
  <div class="text-center py-3">
    <div>
      <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><b>Hexo</b></a>
      <i class="iconfont icon-love"></i>
      <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"> <b>Fluid</b></a>
    </div>
    

    

    
  </div>
</footer>

<!-- SCRIPTS -->
<script  src="https://cdn.staticfile.org/jquery/3.4.1/jquery.min.js" ></script>
<script  src="https://cdn.staticfile.org/popper.js/1.16.1/umd/popper.min.js" ></script>
<script  src="https://cdn.staticfile.org/twitter-bootstrap/4.4.1/js/bootstrap.min.js" ></script>
<script  src="https://cdn.staticfile.org/mdbootstrap/4.13.0/js/mdb.min.js" ></script>
<script  src="/myblog/js/main.js" ></script>


  <script  src="/myblog/js/lazyload.js" ></script>



  
  <script  src="https://cdn.staticfile.org/tocbot/4.10.0/tocbot.min.js" ></script>
  <script>
    $(document).ready(function () {
      var navHeight = $('#navbar').height();
      var toc = $('#toc');
      var boardCtn = $('#board-ctn');
      var boardTop = boardCtn.offset().top;
      var tocLimMax = 2 * boardTop + boardCtn.height();

      $(window).scroll(function () {
        var tocLimMin = $('#toc-start').offset().top - navHeight;
        var scroH = document.body.scrollTop + document.documentElement.scrollTop;

        if (tocLimMin <= scroH && scroH <= tocLimMax) {
          toc.css({
            'display': 'block',
            'position': 'fixed',
            'top': navHeight,
          });
        } else if (scroH <= tocLimMin) {
          toc.css({
            'position': '',
            'top': '',
          });
        } else if (scroH > tocLimMax) {
          toc.css('display', 'none');
        }
      });
      tocbot.init({
        tocSelector: '#tocbot',
        contentSelector: '.post-content',
        headingSelector: 'h1,h2,h3,h4,h5,h6',
        linkClass: 'tocbot-link',
        activeLinkClass: 'tocbot-active-link',
        listClass: 'tocbot-list',
        isCollapsedClass: 'tocbot-is-collapsed',
        collapsibleClass: 'tocbot-is-collapsible',
        scrollSmooth: true,
        headingsOffset: -boardTop
      });
      if ($('.toc-list-item').length > 0) {
        $('#toc > p').css('visibility', 'visible');
      }
      var offset = boardCtn.css('margin-right')
      $('#toc-ctn').css({
        'right': offset
      })
    });
  </script>





  <script defer src="https://cdn.staticfile.org/clipboard.js/2.0.6/clipboard.min.js" ></script>
  <script  src="/myblog/js/clipboard-use.js" ></script>








<!-- Plugins -->



  <script  src="https://cdn.staticfile.org/prettify/188.0.0/prettify.min.js" ></script>
  <script>
    $(document).ready(function () {
      $('pre').addClass('prettyprint  linenums');
      prettyPrint();
    })
  </script>



  <script  src="https://cdn.staticfile.org/typed.js/2.0.11/typed.min.js" ></script>
  <script>
    var typed = new Typed('#subtitle', {
      strings: [
        '  ',
        "Vue学习笔记&nbsp;",
      ],
      cursorChar: "_",
      typeSpeed: 70,
      loop: false,
    });
    typed.stop();
    $(document).ready(function () {
      $(".typed-cursor").addClass("h2");
      typed.start();
    });
  </script>



  <script  src="https://cdn.staticfile.org/anchor-js/4.2.2/anchor.min.js" ></script>
  <script>
    anchors.options = {
      placement: "right",
      visible: "hover",
      
    };
    var el = "h1,h2,h3,h4,h5,h6".split(",");
    var res = [];
    for (item of el) {
      res.push(".markdown-body > " + item)
    }
    anchors.add(res.join(", "))
  </script>



  <script  src="/myblog/js/local-search.js" ></script>
  <script>
    var path = "/myblog/local-search.xml";
    var inputArea = document.querySelector("#local-search-input");
    inputArea.onclick = function () {
      getSearchFile(path);
      this.onclick = null
    }
  </script>



  <script defer src="https://cdn.staticfile.org/fancybox/3.5.7/jquery.fancybox.min.js" ></script>
  <script>
    $("#post img:not(.no-zoom img, img[no-zoom])").each(
      function () {
        var element = document.createElement("a");
        $(element).attr("data-fancybox", "images");
        $(element).attr("href", $(this).attr("src"));
        $(this).wrap(element);
      }
    );
  </script>












</body>
</html>
